Search code examples
androidandroid-service

bound service methods are accessible in Activity, even after it is unbound and stopped


Consider this sequence:

startService > bindService > getRandomNumber > unbindService > stopService > getRandomNumber

According to my understanding, after I unbind a service with activity, I shouldn't have been able to access the methods in service, but I'm still able to access them after unbinding and even after stopping the service.

Any explanation for this behavior?

I have used BIND_AUTO_CREATE flag and the method which is still accessible is a simple random number generator method, which doesn't depend on any other object.

Here is my activity:

public class MainActivity extends AppCompatActivity {

private TextView textView;
private Intent serviceIntent;
private MyService.MyServiceBinder myServiceBinder;
ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        myServiceBinder = ((MyService.MyServiceBinder) service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    textView = findViewById(R.id.threadUpdate);
    serviceIntent = new Intent(this, MyService.class);
}

public void startService(View view) {
    startService(serviceIntent);

}

public void stopService(View view) {
    stopService(serviceIntent);
}

public void getRandomNumber(View view) {
    String str = "Is binder alive :" + myServiceBinder.isBinderAlive() 
            + "\n" + "ServiceConnection :" + connection + "\n"
            + "getRandomNum :" + myServiceBinder.getRandomNumber();

    textView.setText(str);
}

public void bindService(View view) {
    bindService(serviceIntent, connection, BIND_AUTO_CREATE);
}

public void unBindService(View view) {
    unbindService(connection);
}
}

Here is my service:

public class MyService extends Service {
private static final String TAG = "FromMyService";

public MyService() {
}

@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "Service bound");
    return new MyServiceBinder();
}

public class MyServiceBinder extends Binder {
    public int getRandomNumber() {
        Log.d(TAG, "Service getRandomNumber");
        return MyService.this.getRandomNumber();
    }
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "Service Started");
    return Service.START_STICKY;
}

public int getRandomNumber() {
    Log.d(TAG, "Service getRandomNumber");
    return (int) (Math.random() * 100);
}

@Override
public void onRebind(Intent intent) {
    super.onRebind(intent);
    Log.d(TAG, "Service reBound");
}

@Override
public boolean onUnbind(Intent intent) {
    Log.d(TAG, "Service unBound");
    return super.onUnbind(intent);
}

@Override
public void onDestroy() {
    Log.d(TAG, "Service Destroyed");
    super.onDestroy();
}
}

Here is the log output:

    05-19 17:28:29.488 28077-28077/com.thnki.learning D/FromMyService:
    Service Started
    05-19 17:28:32.230 28077-28077/com.thnki.learning D/FromMyService: Service bound
    05-19 17:28:33.966 28077-28077/com.thnki.learning D/FromMyService: Service getRandomNumber
    Service getRandomNumber
    05-19 17:28:40.094 28077-28077/com.thnki.learning D/FromMyService: Service unBound
    05-19 17:28:42.818 28077-28077/com.thnki.learning D/FromMyService: Service Destroyed
    05-19 17:28:44.368 28077-28077/com.thnki.learning D/FromMyService: Service getRandomNumber
    Service getRandomNumber
    05-19 17:28:46.522 28077-28077/com.thnki.learning D/FromMyService: Service getRandomNumber
    Service getRandomNumber

Solution

  • Bounded and started are two different types of Service. You can create a service that is both started and bound. That is, you can start a service by calling startService(), which allows the service to run indefinitely, and you can also allow a client to bind to the service by calling bindService().

    You are doing as follows :-

     startService > bindService > unbindService > stopService
    

    This Service is started Services which is bounded with an Activity. So when is Unbind system does not stop the Service you must explicitly stop the service by calling stopSelf() or stopService().

    PS:- If Service is serving to some SActivity the make it Bounded only no need to call startService, in this case Service will automatically destoy after last unbind.

    Note that if a stopped service still has ServiceConnection objects bound to it with the BIND_AUTO_CREATE set, it will not be destroyed until all of these bindings are removed. See the Service documentation for more details on a service's lifecycle.

    Edit:- Well in your case Service is no longer running after unbind . You are only able to call the method cause you have reference of Binder that does not mean its running. Keep that in mind Service is an Component To test it you can call the method below on each stage.

    private boolean isServiceRunning(Class<?> className) {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (className.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }
    
    
    
    if(isServiceRunning(MyService.class)){
                    Log.e("Service","Running");
                }else{
                    Log.e("Service","NotRunning");
                }
    

    unbindService() official definition says

    Disconnect from an application service. You will no longer receive calls as the service is restarted, and the service is now allowed to stop at any time.