b0wter
b0wter

Reputation: 148

Lifespan of Android service

I am trying to understand how services work in Android and read the Android documentation for bound services: http://developer.android.com/guide/components/bound-services.html For a later project I need a service that runs in the background constantly and that can be interacted with through the application. The documentation states that you can also bind to a service that has been started by startService(). However, I have some trouble getting it to work properly.

The service is very simple. Its only purpose is to supply a counter (I've skipped the imports to not mess the code up unnecessarily):

package com.test.servicetester;

public class LocalService extends Service {
private final IBinder mBinder = new LocalBinder();

private int mCounter = 0;

public class LocalBinder extends Binder {
    LocalService getService() {
        // Return this instance of LocalService so clients can call public methods
        return LocalService.this;
    }
}

private void createNotification(){

    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.roll)
        .setContentTitle("my notification")
        .setContentText("Hello World!")
        .setProgress(100, 33, false)
        .setOngoing(true)
        .addAction(R.drawable.roll, "Titel", pIntent);

    NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(1337, mBuilder.build());
}

@Override
public void onStart(Intent intent, int startId){
    createNotification();
}

@Override
public IBinder onBind(Intent intent) {
    //createNotification();
    Toast.makeText(this, "The service has been bound.", Toast.LENGTH_SHORT).show();
    return mBinder;
}

/** method for clients */
public int getNumber() {
    mCounter++;
    return mCounter;
}

@Override
public void onDestroy(){
    NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.cancelAll();
}
}

The activity from which I control the service contains two buttons, one to get a random number and a second one to kill the service:

package com.wursti.servicetest0r;

import com.wursti.servicetest0r.LocalService.LocalBinder;

public class MainActivity extends Activity {

LocalService mService;
boolean mBound = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

@Override
protected void onStart(){
    super.onStart();
    // bind to local service
    if(!isServiceRunning())
        startService(new Intent(this,LocalService.class));
    else
        Toast.makeText(this, "Service is already running.", Toast.LENGTH_SHORT).show();

    Intent intent = new Intent(this, LocalService.class);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}

private boolean isServiceRunning(){
    ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    for(RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if(LocalService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

@Override
protected void onStop() {
    super.onStop();
    // unbind from the service
    if(mBound) {
        unbindService(mConnection);
        mBound = false;
    }
}

public void onButtonClick(View v) {
    if(mBound) {
        int num = mService.getNumber();
        Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
    }
}

public void onKillServiceClick(View v) {
    mBound = false; // <-- this line was edited because of a comment
    stopService(new Intent(this, LocalService.class));
    unbindService(mConnection);
}

/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName className, IBinder service) {
        // we've bound to LocalService, cast the IBinder and get LocalService instance
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0){
        mBound = false;
    }
};
}

The thing that happens is the following: I start the application and the service is started and the notification appears. If I click the appropriate button I get toats with the number counted correctly. I can switch back to the launcher, reopen the app and will get a message that service was already started and has been bound successfully. However, if I click the kill service button I the notification disappears but I can still get numbers from the service if I use the other button. This is what confuses me... the notification is destroyed in the services onDestroy() method. Therefore it should no longer exist? Why can it still supply numbers? After killing the service if I switch back to the launcher the application crashes and logcat says:

07-05 10:44:21.964: E/AndroidRuntime(792): java.lang.RuntimeException: Unable to stop activity {com.wursti.servicetest0r/com.wursti.servicetest0r.MainActivity}: java.lang.IllegalArgumentException: Service not registered: com.wursti.servicetest0r.MainActivity$1@40e81200
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3415)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3469)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.ActivityThread.access$1200(ActivityThread.java:141)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1287)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.os.Handler.dispatchMessage(Handler.java:99)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.os.Looper.loop(Looper.java:137)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.ActivityThread.main(ActivityThread.java:5041)
07-05 10:44:21.964: E/AndroidRuntime(792):  at java.lang.reflect.Method.invokeNative(Native Method)
07-05 10:44:21.964: E/AndroidRuntime(792):  at java.lang.reflect.Method.invoke(Method.java:511)
07-05 10:44:21.964: E/AndroidRuntime(792):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
07-05 10:44:21.964: E/AndroidRuntime(792):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
07-05 10:44:21.964: E/AndroidRuntime(792):  at dalvik.system.NativeStart.main(Native Method)
07-05 10:44:21.964: E/AndroidRuntime(792): Caused by: java.lang.IllegalArgumentException: Service not registered: com.wursti.servicetest0r.MainActivity$1@40e81200
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:921)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.ContextImpl.unbindService(ContextImpl.java:1451)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.content.ContextWrapper.unbindService(ContextWrapper.java:484)
07-05 10:44:21.964: E/AndroidRuntime(792):  at com.wursti.servicetest0r.MainActivity.onStop(MainActivity.java:61)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.Instrumentation.callActivityOnStop(Instrumentation.java:1205)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.Activity.performStop(Activity.java:5246)
07-05 10:44:21.964: E/AndroidRuntime(792):  at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3410)
07-05 10:44:21.964: E/AndroidRuntime(792):  ... 11 more

Honestly I don't have any idea on how continue from here, any help is appreciated :)

Upvotes: 1

Views: 699

Answers (1)

Ganapathy C
Ganapathy C

Reputation: 5999

unbindService(mConnection);

in onStop is called even after you are killing service before.

may be that's the error.

try handling that!!

Upvotes: 2

Related Questions