android 4.4.X:taskAffinity&launchmode vs. Activity生命周期

 拍友2502935047 发布于 2023-01-08 13:23

我开发了一个简单的应用程序,它解释了我注意到的Android 4.4.X设备上的一些奇怪的行为.

假设我想要进行2次"主要"活动,其中第一次活动表示"Hello"(通过启动"HelloActivity")每秒恢复一次,第二次android:launchMode="singleTask" android:taskAffinity=".MyAffinity"定义.第二个是由第一个开始的.

我的守则

清单非常简单:





    
        
            

            

            
        
    

    
    

    
    

MainActivity在按钮单击时启动AffinityTestActivity并记录其生命周期.它还会在每次恢复时启动HelloActivity:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        System.out.println(this+" onCreate");
        super.onCreate(savedInstanceState);

        Button b = new Button(MainActivity.this);
        b.setText("START AFFINITY TEST ACTIVITY");
        b.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                System.out.println(this+" starts "+AffinityTestActivity.class.getSimpleName());
                Intent intent = new Intent(MainActivity.this, AffinityTestActivity.class);
                startActivity(intent);
            }
        });
        setContentView(b);
    }

    private boolean skipHello = true;

    @Override
    protected void onResume() {
        System.out.println(this+" onResume");
        super.onResume();

        if (!skipHello) {
            System.out.println(this+" starts "+HelloActivity.class.getSimpleName());
            Intent intent = new Intent(MainActivity.this, HelloActivity.class);
            startActivity(intent);
            skipHello = true;
        } else {
            skipHello = false;
        }
    }

    @Override
    protected void onPause() {
        System.out.println(this+" onPause");
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        System.out.println(this+" onDestroy");
        super.onDestroy();
    }

}

AffinityTestActivity在按钮单击时调用finish()并记录其生命周期:

public class AffinityTestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        System.out.println(this+" onCreate");
        super.onCreate(savedInstanceState);

        Button b = new Button(AffinityTestActivity.this);
        b.setText("FINISH");
        b.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                System.out.println(this+" finishes");
                finish();
            }
        });
        setContentView(b);
    }

    @Override
    protected void onResume() {
        System.out.println(this+" onResume");
        super.onResume();
    }

    @Override
    protected void onPause() {
        System.out.println(this+" onPause");
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        System.out.println(this+" onDestroy");
        super.onDestroy();
    }
}

HelloActivity实际上与AffinityTestActivity相同 - 它只有按钮来调用finish()和printlns来记录它的生命周期.

测试场景

    启动MainActivity.

    启动AffinityTestActivity.

    完成AffinityTestActivity(当AffinityTestActivity完成时,恢复MainActivity并启动HelloActivity).

    分析输出.

日志

Android 4.4.2和4.4.3 :(在Nexus 7 II和三星Galaxy S5上测试)正如您所看到的,日志以HelloActivity的onPause结束,这没有意义(HelloActivity在步骤3中显示在顶部).此外,AffinityTestActivity不会被破坏,MainActivity也不会被暂停.

06-20 11:13:20.547: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onCreate
06-20 11:13:20.557: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onResume
06-20 11:13:25.371: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity$1@41f6e5c0 starts AffinityTestActivity
06-20 11:13:25.581: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onPause
06-20 11:13:25.591: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity@41f6a480 onCreate
06-20 11:13:25.611: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity@41f6a480 onResume
06-20 11:13:36.452: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity$1@41f1ede8 finishes
06-20 11:13:36.662: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity@41f6a480 onPause
06-20 11:13:36.682: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onResume
06-20 11:13:36.682: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 starts HelloActivity
06-20 11:13:36.782: I/System.out(18650): com.example.affinitylaunchmodebugtest.HelloActivity@41f8dbb8 onCreate
06-20 11:13:36.802: I/System.out(18650): com.example.affinitylaunchmodebugtest.HelloActivity@41f8dbb8 onResume
06-20 11:13:36.852: I/System.out(18650): com.example.affinitylaunchmodebugtest.HelloActivity@41f8dbb8 onPause

较旧的Android版本(<4.4.2,在2.3.5.,4.1.2和4.2.1设备上测试,4.0.3模拟器)按预期工作 - 在onResume和AffinityTestActivity被销毁后,HelloActivity不会暂停:

06-20 11:16:30.867: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onCreate
06-20 11:16:30.907: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onResume
06-20 11:16:34.157: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity$1@40f9b350 starts AffinityTestActivity
06-20 11:16:34.277: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onPause
06-20 11:16:34.297: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onCreate
06-20 11:16:34.357: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onResume
06-20 11:16:38.687: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity$1@40fad640 finishes
06-20 11:16:38.707: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onPause
06-20 11:16:38.717: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onResume
06-20 11:16:38.717: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 starts HelloActivity
06-20 11:16:38.747: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onPause
06-20 11:16:38.777: I/System.out(3296): com.example.affinitylaunchmodebugtest.HelloActivity@40fbdd48 onCreate
06-20 11:16:38.827: I/System.out(3296): com.example.affinitylaunchmodebugtest.HelloActivity@40fbdd48 onResume
06-20 11:16:39.877: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onDestroy

我的问题

为什么我的HelloActivity在Android 4.4.X设备上启动并在顶部显示后暂停?

我如何避免它并强制应用程序具有"正常"活动生命周期,因为较旧的Android版本(<4.4.2)会这样做?

我开发的应用程序要复杂得多,并且与其活动的生命周期一起工作,这种行为违反了我的应用程序的功能.

非常感谢你!

1 个回答
  • 我根据您提供的代码创建了一个项目,并且我能够在自己的Nexus 7上重新创建您的问题.虽然我没有具体的学术答案,但我最好的解释如下:

    1)MainActivity已启动

    2)点击按钮.AffinityTestActivity在新任务中启动.

    3)点击按钮.AffinityTestActivity完成.

    4)MainActivity在旧任务中恢复.

    5)在MainActivity的onResume中,HelloActivity的意图在同一任务中被调用.

    6)经过一些修补之后,我的理论中的神秘部分:将旧任务带到前台的某些部分在onResume调用期间继续与MainActivity(旧任务的根)进行交互.此交互导致HelloActivity的onPause方法被触发(可能不是OS开发人员想要的).虽然这不是最令人满意的答案(鉴于我对操作系统级调度代码和时序问题的经验有限),我的实验指出了这些方面.我对这种干扰的第一个线索是在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
    

    如您所见,在HelloActivity完成之后,甚至都没有调用MainActivity的onPause方法.这也不对.对我来说,这表明在任务被带到前台时在onResume内启动一个活动会在生命周期中引起一些意外的冲突.

    要看看如果我给活动/任务一秒钟完成任何看不见的处理会发生什么,我使用处理程序来调用MainActivity中的HelloActivity意图:

     @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;
        }
    }
    

    这导致了更好的行为.HelloActivity按原样运行,并且未调用onPause.显然,这对于工作代码并不理想,但它表明只需将执行时间向前移动一秒即可解决问题.更多内部调度的证据在任务中发生冲突.

    接下来,我尝试给HelloActivity自己的任务:

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

    (对于记录,这种配置没有多大意义,但我认为它反映了真实项目中具有更合理用途的场景.)

    在这种情况下,一切正常.HelloActivity的生命周期不会干扰MainActivity的生命周期.但是,它现在有自己的任务的开销和运行活动的伴随问题singleTask(按"主页"按钮并重新打开应用程序将带您进入MainActivity,即使它是最后一个,HelloActivity也无法在其新任务中访问关闭应用程序之前查看的活动).

    我最好的建议是找到一种方法来避免这种特殊情况.:)它似乎是Android的更高版本中的一个错误,虽然是一个奇怪的边缘情况.如果这不是一个选择,你可以追求我曾经绕过它的路线之一.我已经尝试了其他一些东西,但很难解决这样一个事实,即调度是在我们掌握的操作系统级别之外进行控制的.

    对不起,我无法给你一个更深入的答案,但这就是我现在所拥有的一切!

    2023-01-08 13:26 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有