android 4.4.X: taskAffinity & launchmode vs. Activity lifecycle

后端 未结 1 1297
说谎
说谎 2021-02-08 13:37

I developed a simple application, which demostrates some strange behaviour on Android 4.4.X devices I noticed.

Lets say I want to have 2 \"main\" activities, where the f

相关标签:
1条回答
  • 2021-02-08 13:58

    I've created a project based on the code you provided, and I was able to recreate your issue on my own Nexus 7. While I don't have a concrete, academic answer for you, my best explanation is the following:

    1) MainActivity is started

    2) Button clicked. AffinityTestActivity is started in a new task.

    3) Button clicked. AffinityTestActivity finishes.

    4) MainActivity resumes within the old task.

    5) In MainActivity's onResume, the intent for HelloActivity is called within the same task.

    6) The mysterious part which is my theory after a bit of tinkering: Some part of bringing the old task to the foreground continues to interact with MainActivity, the root of the old task, during its onResume call. This interaction causes the HelloActivity's onPause method to be triggered (probably not intended by the OS developers). While this isn't the most satisfying answer (given my limited experience with OS-level scheduling code and timing issues), my experiments point to something along those lines. My first clue to this interference was this frequent error seen in logcat:

    06-24 11:06:28.015  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.MainActivity@64e05830 onPause
    06-24 11:06:28.055  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.AffinityTestActivity@64e22fc0 onCreate
    06-24 11:06:28.075  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.AffinityTestActivity@64e22fc0 onResume
    06-24 11:06:28.175      665-685/? I/ActivityManager﹕ Displayed com.stackoverflow/.AffinityTestActivity: +163ms
    06-24 11:06:29.997  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.AffinityTestActivity$1@64e24bf8 finishes
    06-24 11:06:30.007  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.AffinityTestActivity@64e22fc0 onPause
    06-24 11:06:30.027  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.MainActivity@64e05830 onResume
    06-24 11:06:30.027  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.MainActivity@64e05830 starts HelloActivity
    06-24 11:06:30.027     665-6346/? I/ActivityManager﹕ START u0 {cmp=com.stackoverflow/.HelloActivity} from pid 27200
    06-24 11:06:30.117  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.HelloActivity@64e33b18 onCreate
    06-24 11:06:30.127  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.HelloActivity@64e33b18 onResume
    06-24 11:06:30.137  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.HelloActivity@64e33b18 onPause
    06-24 11:06:30.287      665-685/? I/ActivityManager﹕ Displayed com.stackoverflow/.HelloActivity: +182ms
    06-24 11:06:32.389  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.HelloActivity$1@64e356b0 finishes
    06-24 11:06:32.389  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.HelloActivity@64e33b18 onDestroy
    06-24 11:06:32.399  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.MainActivity@64e05830 onPause
    06-24 11:06:32.399  27200-27200/com.stackoverflow E/ActivityThread﹕ Performing pause of activity that is not resumed: {com.stackoverflow/com.stackoverflow.MainActivity}
    java.lang.RuntimeException: Performing pause of activity that is not resumed: {com.stackoverflow/com.stackoverflow.MainActivity}
    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3015)
    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3003)
    at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:2981)
    at android.app.ActivityThread.access$1000(ActivityThread.java:135)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1207)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5001)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
    06-24 11:06:32.409  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.MainActivity@64e05830 onResume
    06-24 11:06:32.769  27200-27200/com.stackoverflow I/System.out﹕ com.stackoverflow.AffinityTestActivity@64e22fc0 onDestroy
    

    As you can see, MainActivity's onPause method wasn't even called until after HelloActivity was finished. That's not right either. That, to me, shows that starting an activity within onResume while the task is being brought to the foreground is causing some unintended conflicts in the lifecycle.

    To see what happened if I gave the activity/task a second to complete any unseen processing, I used a handler to call the HelloActivity intent in MainActivity:

     @Override
    protected void onResume() {
        System.out.println(this + " onResume");
        super.onResume();
    
        if (!skipHello) {
            System.out.println(this+" starts "+HelloActivity.class.getSimpleName());
    
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    Intent intent = new Intent(MainActivity.this, HelloActivity.class);
                    startActivity(intent);
                }
            }, 1000);
    
            skipHello = true;
        } else {
            skipHello = false;
        }
    }
    

    This resulted in much better behavior. HelloActivity acted as it should, and onPause wasn't called. Obviously this isn't ideal for working code, but it shows that simply moving execution time forward by a second fixed the problem. More evidence of internal scheduling conflict within the task.

    Next, I tried giving HelloActivity its own task as well:

    <activity
        android:label="HELLO"
        android:name="com.stackoverflow.HelloActivity"
        android:configChanges="keyboardHidden|orientation|screenSize"
        android:launchMode="singleTask"
        android:taskAffinity=".DifferentTask">
    </activity>
    

    (For the record, this configuration doesn't make much sense, but I assume it's reflecting a scenario in your real project that has a more logical purpose.)

    Under this scenario, everything works fine. HelloActivity's lifecycle does not interfere with MainActivity's lifecycle. However, it now has the overhead of its own task and the accompanying problems of running an activity as singleTask (hitting the "Home" button and reopening the app will take you to MainActivity, leaving HelloActivity inaccessible in its new task even though it was the last activity viewed before closing the app).

    My best recommendation would be to find a way to avoid this particular scenario. :) It seems like it's a bug within later versions of Android, albeit a strange edge case. If that's not an option, you could pursue one of the routes I used to get around it. I've tried a couple other things, but it's difficult to get around the fact that the scheduling is controlled at an OS level outside our grasp.

    Sorry that I couldn't get you a more in-depth answer, but that's all I've got for now!

    0 讨论(0)
提交回复
热议问题