简体   繁体   中英

Wait for activity is destroyed

I have a question about life cycle.

I have 2 activities. (Just call it A and B). In A which is MainActivity I have a button that call Activity B. At activity B, pressing back button will call the finish() .

The point is it's okay when I call finish() , wait a while and than call B again, it's okay. But when I call finish() and immediately call B again than previous B's onDestroy() is called after new B's onCreate() , onResume() .

It's problem for me because I handle some static MediaPlayer on onResume() , onPause() ... everywhere.

@Override
protected void onResume(){
    super.onResume();

    if (mediaPlayer != null)
        mediaPlayer.start();
}

@Override
protected void onPause(){
    super.onPause();

    if(mediaPlayer != null)
        mediaPlayer.pause();
}

@Override
protected void onDestroy(){
    super.onDestroy();
    if(mediaPlayer != null)
        mediaPlayer.release();
        mediaPlayer = null;
}

So if I press back and call B fast again, it resume the previous sound short and than stop. Another class controls the mediaPlayer so I can't remove the static field.

I think I can handle this by waiting onDestroy( ). Is there any way to make MainActivity(A) to wait until B is completely destroyed?

There is a ActivityLifeCycleCallBack Listner for Application class, where you can know Which activity is created and which is Destroyed .

This will help you to easily implement your current logic Application.ActivityLifecycleCallbacks

You can introduce counted lock, like:

class X extends Activity {

    private static int runningTimes = 0;

    private synchronized void lockPlayer() {
        ++runningTimes;
    }

    private synchronized boolean releasePlayer() {
        return (0 == --runningTimes);
    }

    @Override
    onCreate(...) {
        super.onCreate(...);
        lockPlayer();
    }

    @Override
    protected void onDestroy(){
        if(releasePlayer() && mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
        super.onDestroy();
    }

}

I think both Activities run on the same UI thread in onCreate/onDestroy? Because that proposed synchronization is not robust enough to survive truly parallel execution. If they are on the same UI thread, actually the synchronized can be removed from ++/-- methods, as only the order of onCreate/onDestroy is problem, not simultaneous run of them.

I would also suggest to call super.on<EndingEvent>() to call at the end of your overridden handler, not at the start of it (you will probably never encounter real bug from this, but it just makes sense, if you read the source "procedurally" in mind).


Warning: in case you don't receive correctly paired onCreate/onDestroy, the counter may get into unsynced value... probably it wouldn't do much harm, as you will simply not release the player ever then. But I have generally good experience with Android OS calling onCreate/onDestroy reliably, except situations when whole OS is already on the brink of crash.

You have no control over when onDestroy() gets called, so waiting for that will not work.

In your case you should either call mediaPlayer.release() in onPause() and create it in onResume() , or just leave it existing independently of the lifecycle of the activities

Well, I think this could work:

class B extends Activity {
     public static boolean destroyed = 1;
     .
     .
     .
     public void onCreate(Bundle args) {
          destroyed = 0;
          .
          .
          .
     }
     public void onDestroy() {
          .
          .
          .
          destroyed = 1;
     }
}
class A extends Activity {
     .
     .
     .
     buttonB.setOnItemClickListener(new OnItemClickListener() {
          public void onClick(View v) {
              while (B.destroyed == 0);
              Intent i = new Intent();
              .
              .
              .
              startActivity(i, B.class);
          }

     })
}

The "B.destroyed == 0" part will wait until B is destroyed, and then it will start the new intent.

Note: there's also isDestroyed() method starting from API17 which you can call on activity B, smth like: https://developer.android.com/reference/android/app/Activity.html#isDestroyed()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM