- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我开发了一个简单的应用程序,它演示了我注意到的 Android 4.4.X 设备上的一些奇怪行为。
假设我想要有 2 个“主要” Activity ,其中第一个在每次恢复时说“你好”(通过启动“HelloActivity”),第二个有 android:launchMode="singleTask"android:taskAffinity=".MyAffinity"
定义。第二个由第一个开始。
Manifest 非常简单:
<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:
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。
Android 4.4.2 和 4.4.3:(在 Nexus 7 II 和 Samsung Galaxy S5 上测试)可以看到,log以HelloActivity的onPause结束,这是没有意义的(步骤3中HelloActivity显示在最上面)。此外,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 模拟器上测试)按预期工作 - HelloActivity 在 onResume 后未暂停并且 AffinityTestActivity 被销毁:
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
我开发的应用程序要复杂得多,并且会处理其 Activity 的生命周期,这种行为违反了我的应用程序的功能。
非常感谢!
最佳答案
我已经根据您提供的代码创建了一个项目,并且能够在我自己的 Nexus 7 上重现您的问题。虽然我没有给您一个具体的、学术性的答案,但我最好的解释如下:
1) MainActivity 启动
2) 单击按钮。 AffinityTestActivity 在新任务中启动。
3) 单击按钮。 AffinityTestActivity 完成。
4) MainActivity 在旧任务中恢复。
5) 在 MainActivity 的 onResume 中,在同一个任务中调用了 HelloActivity 的 Intent 。
6) 神秘的部分是我经过一些修补后的理论:将旧任务带到前台的某些部分在其 onResume 调用期间继续与旧任务的根 MainActivity 交互。此交互会导致触发 HelloActivity 的 onPause 方法(操作系统开发人员可能无意)。虽然这不是最令人满意的答案(考虑到我在操作系统级调度代码和计时问题方面的经验有限),但我的实验指向了一些类似的东西。我对这种干扰的第一个线索是在 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 中启动 Activity 会导致生命周期中出现一些意外冲突。
为了查看如果我给 Activity/任务一秒钟来完成任何看不见的处理会发生什么,我使用了一个处理程序来调用 MainActivity 中的 HelloActivity Intent :
@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>
(郑重声明,此配置没有多大意义,但我认为它反射(reflect)了您的真实项目中具有更合乎逻辑目的的场景。)
在这种情况下,一切正常。 HelloActivity 的生命周期不会干扰 MainActivity 的生命周期。但是,它现在有自己的任务的开销以及作为 singleTask
运行 Activity 的伴随问题(点击“Home”按钮并重新打开应用程序将带您到 MainActivity,使 HelloActivity 在其新任务,即使它是关闭应用程序之前查看的最后一个 Activity )。
我最好的建议是找到一种方法来避免这种特殊情况。 :) 这似乎是 Android 更高版本中的一个错误,尽管是一种奇怪的边缘情况。如果那不是一种选择,您可以采用我曾经绕过它的路线之一。我已经尝试了一些其他的东西,但是很难回避这样一个事实,即调度是在我们无法控制的操作系统级别上控制的。
很抱歉,我无法为您提供更深入的答案,但这就是我目前所能得到的!
关于android 4.4.X : taskAffinity & launchmode vs. Activity 生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24325122/
案例 I:- 当 Intent Flag 覆盖 Manifest 时 在 list 文件中,我将 Activity_B 定义为 singleTop。这些是 list 文件中的相关行:- .... .
如果我们有 2 个 Activity,A 和 B,它们都在 AndroidManifest.xml 中定义为 singleTask,当A启动B时,A将被关闭(onDestroy()被立即调用)。为什么
我对 Android 中不同的 Activity 启动模式感到非常困惑。我知道它与 Activity 堆栈有关,这对我来说也不太清楚。如果能通过简单的用例对每个启动模式进行简短说明,我将不胜感激。 最
我已声明我的 Activity 的启动模式为 singleTask。如果我启动我的应用程序,按主页按钮,转到电子邮件客户端(在本例中为 gmail)并使用我的应用程序预览附件,我我在 Android
我正在实现自定义启动器。我有两个 Activity :启动模式为 singleInstance 或 singleTask 的 Activity A,以及 Activity B。 Activity A
我的应用程序中有 2 个 Activity 。 A Activity 是启动器 Activity 。当我第一次运行应用程序时,启动器 Activity 会运行,但是当我按下主页按钮并通过单击应用程序图
我有一个 WidgetResultActivity 和一个 NotificationResultActivity,我设置了它们的 launchmode=singleInstance。但是它们有不同的行
我正在 Unity 上构建一个 Android 游戏,它有一个打开新 Activity 的按钮。 问题是在构建 APK 时,无论我在自定义 AndroidManifest.xml 中放入什么,Unit
我知道有一些帖子可以解答我要问的问题,但我找不到任何正确答案。 根据我的理解,如果您的主要 Activity (我们称它为 A)的启动模式设置为 singleTask,并且 A 已启动 Activit
关于 http://developer.android.com/guide/topics/manifest/activity-element.html他们将 launchMode 的可能值列为 a
我有 2 个 Activity:Activity A 和 Activity B。Activity A 的启动模式是标准的,Activity B 的启动模式是 singleTask。
我一直在学习 Android,并且遇到了 launchMode="singleTask"的问题。文档指出,当使用此属性时,Activity 始终作为根 Activity 启动到新任务中。其次,文档指出
我有一个 SearchActivity,它在 list 中用 android:launchMode="singleTop" 定义。 我的 SearchActivity 包括一个供用户输入查询的 Sea
一个Activity有四种启动模式,standard、singletop、singletask和singleInstance。前三者比较容易理解,应用广泛。但是到现在为止,我没有发现任何使用singl
什么是一些应用程序示例或用例,其中(singleInstance、singleTask、singleTop)服务于必要的目的。即为什么人们会偏爱一种启动模式而不是另一种?到目前为止,我对它们的体验是严
我一直在想为什么我的 Intent 不会将字符串数据从一个 Activity 传输到另一个 Activity ?我似乎在 list 文件夹中设置了 launchMode = singleTask,当我
这个问题在这里已经有了答案: App completely restarting when launched by icon press in launcher (15 个答案) 关闭 3 年前。
我在我的应用程序中使用了 android:launchMode="singleInstance" 如何在 android api 2.3.3 中完美编译和运行但是当我在基于api 4.0 的andro
我有一个围绕主要 Activity (主菜单)的应用程序。在每个其他应用程序中,都有一个指向此 Activity 的选项菜单项。 起初,我总是在选择这个项目时开始一个新的主要 Activity 。使用
我正在寻找何时使用 launchMode="singleInstance" 的具体示例。我到处阅读,据说很少有场合应该使用它。所以我很惊讶我从来没有看到例子! 我找到的最接近的解释是 here它说:
我是一名优秀的程序员,十分优秀!