Reputation: 354
I'm building a chat application, which uses web socket. I've wrote a service, which is called in Application class. The problem is that, sometimes the mConnection becomes null when I just start the app after the crash. I think that it's because of the service being run on the background even when I quit the app, and when i start it again, it can't create the new service and bind to it. My questions are: Is it a good way of writing the code? And is there a way to stop the service on the application destroy?
public class MyApplication extends Application{
private final AtomicInteger refCount = new AtomicInteger();
public ConnectionService mConnectionService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
ConnectionService.MyBinder b = (ConnectionService.MyBinder) binder;
mConnectionService = b.getService();
Log.d("MyApplication", "MyApplication has been bounded");
}
public void onServiceDisconnected(ComponentName className) {
mConnectionService = null;
Log.d("MyApplication", "MyApplication has been unbounded");
}
};
@Override
public void onCreate() {
Intent intent = new Intent(this, ConnectionService.class);
getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
public ConnectionService getConnectionService() {
refCount.incrementAndGet();
Log.d("MyApplication", "getConnectionService, current: "+refCount);
return mConnectionService;
}
public void releaseConnectionService() {
if (refCount.get() == 0 || refCount.decrementAndGet() == 0) {
mConnectionService.stopSelf();
Log.d("MyApplication", "MyApplication has been stopped ");
}
Log.d("MyApplication", "releaseConnectionService, current: "+refCount);
}
}
And the another class looks something like this:
public class LobbyActivity extends Activity{
ListView lvContacts;
Gson gson;
LoginData mLoginData;
MyReceiver receiver;
ArrayList<User> users;
LobbyAdapter lobbyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gson = new Gson();
Intent intent = getIntent();
String loginDataJson = intent.getStringExtra("LoginData");
mLoginData = gson.fromJson(loginDataJson, LoginData.class);
getActionBar().setTitle(mLoginData.getUsername());
setContentView(R.layout.activity_lobby);
users = new ArrayList<User>();
lvContacts = (ListView)findViewById(R.id.lvContacts);
lobbyAdapter=new LobbyAdapter(users, this);
lvContacts.setAdapter(lobbyAdapter);
Commands cmd = new Commands(getApplicationContext());
cmd.sendCommand(Commands.COMMAND_GET_MANAGER_LIST);
cmd.sendCommand(Commands.COMMAND_GET_USER_LIST);
receiver = new MyReceiver(new Handler()) {
@Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra(ConnectionService.MESSAGE);
String notification = intent.getStringExtra(ConnectionService.NOTIFICATION);
if (message!=null){
try {
switch (Utils.getCommand(message)) {
case Commands.COMMAND_GET_USER_LIST:
ArrayList<User> user = new ArrayList<User>();
user = (gson.fromJson(message, UserList.class)).users;
users.addAll(user);
lobbyAdapter.notifyDataSetChanged();
break;
default:
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter(MainActivity.BROADCAST_ACTION));
}
class UserList{
String cmd;
ArrayList<User> users;
}
@Override
protected void onDestroy() {
super.onDestroy();
((MyApplication)getApplicationContext()).releaseConnectionService();
}
}
The reason why i put the service in the Application class is that i want it to be up as long as the application runs; and also it is needed to be accessed by all the activities.
Upvotes: 1
Views: 1146
Reputation: 2075
Is it a good way of writing the code?
I would say that it's not a good programming practice to start Android app components like Service
or Activity
from Application
class. You should start Service from Activity
or BroadcastReceiver
component. In the end code inside Application onCreate
runs because the new process is created for your application when it starts. This happen if you start app from launcher and main Activity
starts or BroadcastReceiver
has been given a call. At this moment you can start Service
from either of them.
And is there a way to stop the service on the application destroy?
You can stop Service
from Activity's onDestroy()
. If you don't want to stop Service on every configuration change (like screen rotation) you can check in onDestory
method whether it is destroying or only reloading through isChangingConfigurations
method of Activity
and decide to stop or not Service
basing on that knowledge.
Upvotes: 1