Vladislav Kan
Vladislav Kan

Reputation: 354

Service in Application class doing web socket connection crashes

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

Answers (1)

michal.z
michal.z

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

Related Questions