首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android4.4.X: taskAffinity &启动模式与活动生命周期

Android4.4.X: taskAffinity &启动模式与活动生命周期
EN

Stack Overflow用户
提问于 2014-06-20 10:24:21
回答 1查看 2.3K关注 0票数 10

我开发了一个简单的应用程序,它演示了我注意到的Android4.4.X设备上的一些奇怪行为。

让我说,我希望有两个“主”活动,其中第一个说"Hello“(通过启动'HelloActivity')每二次它被恢复,第二个有android:launchMode="singleTask" android:taskAffinity=".MyAffinity"定义。第二个是从第一个开始的。

我的密码

Manifest非常简单:

代码语言:javascript
复制
<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="14" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <activity
        android:name="com.example.affinitylaunchmodebugtest.MainActivity"
        android:configChanges="keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <category android:name="android.intent.category.DEFAULT" />

            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity
        android:label="HELLO"
        android:name="com.example.affinitylaunchmodebugtest.HelloActivity"
        android:configChanges="keyboardHidden|orientation|screenSize">
    </activity>

    <activity
        android:label="AffinityTestActivity"
        android:name="com.example.affinitylaunchmodebugtest.AffinityTestActivity"
        android:configChanges="keyboardHidden|orientation|screenSize"
        android:launchMode="singleTask"
        android:taskAffinity=".MyAffinity">
    </activity>
</application>

MainActivity按一下按钮启动AffinityTestActivity并记录其生命周期。它还在恢复时每秒钟启动一次HelloActivity:

代码语言:javascript
复制
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()并记录其生命周期:

代码语言:javascript
复制
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。

测试场景

  1. 启动MainActivity。
  2. 启动AffinityTestActivity。
  3. Finish AffinityTestActivity (当AffinityTestActivity完成时,MainActivity被恢复,HelloActivity被启动)。
  4. 分析输出。

日志

Android4.4.2和4.4.3:(在Nexus7II和三星GalaxyS5上测试)如您所见,日志以HelloActivity的onPause结束,这是没有意义的(HelloActivity显示在第3步的顶部)。另外,AffinityTestActivity没有被销毁,MainActivity也没有被暂停。

代码语言:javascript
复制
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

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

代码语言:javascript
复制
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在Android4.4.X设备上启动并显示在顶部之后就会暂停呢?
  • 如何避免它并强制应用程序具有“正常”的活动生命周期,就像旧版本(<4.4.2)所做的那样?

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

,非常感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-24 15:33:17

我创建了一个基于您提供的代码的项目,并且能够在我自己的Nexus 7上重新创建您的问题。虽然我没有一个具体的学术答案给您,但我最好的解释是:

1)启动MainActivity

2)按钮点击。AffinityTestActivity是在一个新任务中启动的。

3)按钮点击。AffinityTestActivity完成。

4) MainActivity在旧任务中恢复。

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

6)神秘的部分,这是我的理论,经过一点修补:在老任务的MainActivity调用过程中,一些将旧任务带到前台的部分继续与其进行交互。这种交互导致HelloActivity的onPause方法被触发(可能不是OS开发人员想要的)。虽然这不是最令人满意的答案(考虑到我在操作系统级调度代码和时间问题方面的有限经验),我的实验指出了这方面的一些问题。我对这种干扰的第一条线索是在logcat中经常出现的错误:

代码语言:javascript
复制
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

如您所见,MainActivity的onPause方法甚至在HelloActivity完成后才被调用。这也不对。对我来说,这表明在任务被带到前台时在onResume中启动一个活动会导致生命周期中一些意想不到的冲突。

为了了解如果给活动/任务一秒钟时间来完成任何未见的处理,会发生什么,我使用一个处理程序在MainActivity中调用MainActivity意图:

代码语言:javascript
复制
 @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自己的任务:

代码语言:javascript
复制
<activity
    android:label="HELLO"
    android:name="com.stackoverflow.HelloActivity"
    android:configChanges="keyboardHidden|orientation|screenSize"
    android:launchMode="singleTask"
    android:taskAffinity=".DifferentTask">
</activity>

(请记住,这种配置没有多大意义,但我认为它反映的是一个在您的实际项目中具有更合理目的的场景。)

在这种情况下,一切都正常。HelloActivity的生命周期不影响MainActivity的生命周期。然而,它现在有自己的任务的开销,以及运行singleTask所伴随的问题(按下"Home“按钮并重新打开应用程序将带您到MainActivity,即使这是关闭应用程序之前的最后一次查看,HelloActivity在其新任务中仍然无法访问)。

我最好的建议是找到一种避免这种特殊情况的方法。)这似乎是Android后期版本中的一个bug,尽管这是一个奇怪的边缘情况。如果这不是一种选择,你可以选择一条我用来绕过它的路线。我尝试过其他一些事情,但很难绕过这样一个事实,即调度控制在我们无法控制的操作系统级别上。

很抱歉,我没能给你一个更深入的答案,但这就是我现在所拥有的一切!

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24325122

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档