我有一个Ionic / Cordova应用,该应用大量使用了相机插件,并且在Android上运行时遇到了问题。
如Android Activity Lifecycle docs文档和Cordova's Lifecycle Docs for the Android Platform中所述,当摄像头来到前台时,应用的主要活动将被放入paused
或stopped
中状态在后台。
尽管主要活动处于上述两种状态中,但如果它需要释放内存,则很容易被系统杀死,这种情况在此应用程序中经常发生,足以使用户抱怨。
在测试中,我发现有时在关闭相机后该应用程序会自行重启,而有时活动似乎已经消失在相机后面,因此当用户关闭相机时,该应用程序似乎崩溃了。
阅读了上述文档后,我向由Cordova生成的MainActivty
android代码添加了一些日志记录,以便可以观察使用相机时的状态变化,还向onCreate
添加了未捕获的异常处理程序:
public class MainActivity extends CordovaActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
Log.e("com.xxx.test", "onCreate");
super.onCreate(savedInstanceState);
// enable Cordova apps to be started in the background
Bundle extras = getIntent().getExtras();
if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
moveTaskToBack(true);
}
// Set by <content src="index.html" /> in config.xml
loadUrl(launchUrl);
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
Log.e("com.xxx.test", "onCreate, UNCAUGHT EXCEPTION!!!");
System.exit(2);
}
});
}
@Override
public void onStart() {
Log.e("com.xxx.test", "onStart");
super.onStart();
}
@Override
public void onResume() {
Log.e("com.xxx.test", "onResume");
super.onResume();
}
@Override
public void onPause() {
Log.e("com.xxx.test", "onPause");
super.onPause();
}
@Override
public void onStop() {
Log.e("com.xxx.test", "onStop");
super.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("com.xxx.test", "onDestroy");
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
Log.e("com.xxx.test", "onSaveInstanceState");
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
Log.e("com.xxx.test", "onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
}
}
我运行该应用程序,并过滤logcat
中包含“ com.xxx.test”的行,并显示以下结果:
相机正常操作
//camera button tapped
onPause
onSaveInstanceState
onStop
//user takes photo and dismisses camera
onResume
应用重新启动
到目前为止,一切都很好。现在,如果在关闭相机后应用重新启动,我会得到:
//camera button tapped
onPause
onSaveInstanceState
onStop
//user takes photo and dismisses camera, app restarts itself here
onCreate
onStart
onRestoreInstanceState
onResume
这是我期望在应用程序在后台终止活动时看到的内容-当用户导航回该活动时,系统会重新创建活动并加载任何保存的状态等。这很好,我将能够处理中断。
崩溃
但是,有时日志会这样做:
//camera button tapped
onPause
//sometimes it stops here, sometimes I also get
onSaveInstanceState
//boom! - the app seems to have crashed and the user is taken back to the home screen when dismissing the camera
因此,我怀疑正在发生的事情是系统在活动进入stopped
状态之前就将其杀死,并且没有保存重新启动该活动所需的任何引用。然后,当我们尝试返回该活动时,系统不知道要加载什么,因此仅退出应用程序。
我不是100%肯定是这种情况。也许该应用在其他地方崩溃了,但我对此一无所知。
所以我的问题是,如果系统杀死了Android上处于paused
状态的活动,我们是否应该能够根据需要再次导航回该活动,或者该标准行为是应用程序刚刚退出并且用户必须重新启动吗?如果是这样,是否有任何解决方法?
如果活动应该在不退出应用程序的情况下返回,那么我如何找出导致崩溃的原因?我的异常处理程序从未被调用过,我已经在logcat
的所有行中苦苦跋涉,但是看不到任何东西可以为我提供有关问题所在的任何线索。
我已经使用事件探查器运行该应用程序,尽管内存使用率很高,大约为350mb,但似乎没有任何泄漏会随着拍摄更多照片而使它越来越高。
关于重新创建问题需要拍摄多少张照片,似乎也没有任何规律,有时它会一遍又一遍地重新启动,有时会一遍又一遍地退出,而另一些时候我会混合物。
任何有关如何阻止此类崩溃的想法都值得赞赏。
修改
我一直在浏览日志,试图整理发生的事情的时间表:
因此,用户在应用程序中点击相机按钮,主要活动进入paused
状态,onSaveInstanceState()
被称为...
16:23:10.244 505-505/com.xxx.test I/chromium: [INFO:CONSOLE(24978)] "photo button tapped", source: file:///android_asset/www/build/main.js (24978)
16:23:10.315 505-505/com.xxx.test E/com.xxx.test: onPause
16:23:10.315 505-505/com.xxx.test D/CordovaActivity: Paused the activity.
16:23:10.322 505-505/com.xxx.test E/com.xxx.test: onSaveInstanceState
此后,有一堆摄像机设置日志,但在所有主要活动中,所有日志都消失了,大概是被系统杀死以释放资源...
16:23:11.415 3696-6128/? I/WindowManager: WIN DEATH: Window{2ae98e1d0 u0 com.xxx.test/com.xxx.test.MainActivity}
16:23:11.415 3696-4312/? I/ActivityManager: Process com.xxx.test (pid 505) has died(377,151)
尽管onSaveInstanceState()
被调用,但系统声称没有保存状态...
16:23:11.419 3696-4312/? W/ActivityManager: Force removing ActivityRecord{c76b13bd0 u0 com.xxx.test/.MainActivity t2117}: app died, no saved state
然后大约半秒钟,当相机仍然可见时,系统为我的包裹名称启动一个新过程...
16:23:12.047 3696-9816/? D/MountService: getExternalStorageMountMode : 3
getExternalStorageMountMode : 3
getExternalStorageMountMode : final mountMode=3, uid : 10298, packageName : com.xxx.test
16:23:12.061 3696-9816/? I/ActivityManager: Start proc 6426:com.xxx.test/u0a298 for content provider com.xxx.test/android.support.v4.content.FileProvider
虽然进程6426
的日志记录很少,
16:23:12.062 6426-6426/? E/Zygote: v2
16:23:12.062 6426-6426/? I/libpersona: KNOX_SDCARD checking this for 10298
16:23:12.063 6426-6426/? I/libpersona: KNOX_SDCARD not a persona
16:23:12.063 6426-6426/? E/Zygote: accessInfo : 0
16:23:12.064 6426-6426/? W/SELinux: SELinux selinux_android_compute_policy_index : Policy Index[2], Con:u:r:zygote:s0 RAM:SEPF_SECMOBILE_7.0_0007, [-1 -1 -1 -1 0 1]
16:23:12.064 6426-6426/? I/SELinux: SELinux: seapp_context_lookup: seinfo=untrusted, level=s0:c512,c768, pkgname=com.xxx.test
16:23:12.069 6426-6426/? I/art: Late-enabling -Xcheck:jni
16:23:12.098 6426-6426/? D/TimaKeyStoreProvider: TimaKeyStore is not enabled: cannot add TimaSignature Service and generateKeyPair Service
就是这样。不过,ActivityManager
很快尝试将重新创建的活动移到最前面...
16:23:12.212 3696-5435/? D/ActivityManager: moveToFront() : reason=startedActivity setFocusedActivity isAttached=true TaskRecord{d952617d0 #2117 A=com.xxx.test U=0 StackId=1 sz=2}
16:23:12.213 3696-5435/? D/InputDispatcher: Focused application set to: xxxx
然后相机暂停,即使用户仍然可以看到它...
16:23:12.239 30891-30891/? V/Camera6: onPause
ActivityManager
再次提到了我的包裹名称...
16:23:12.558 3696-6838/? D/ActivityManager: resumeTopActivityInnerLocked() : #1 prevTask=TaskRecord{d952617d0 #2117 A=com.xxx.test U=0 StackId=1 sz=2} next=ActivityRecord{bc76899d0 u0 com.sec.android.app.camera/.AttachActivity t2117} mFocusedStack=ActivityStack{33a525ad0 stackId=1, 2 tasks}
不久之后,MultiScreenManagerService
抱怨任务有多个活动,ActivityManager
开始做更多的事情……
16:23:14.529 3696-13852/? W/MultiScreenManagerService: moveTaskBackToDisplayIfNeeded(): The task has more than one activity
16:23:14.530 3696-13852/? D/ActivityManager: moveToFront() : reason=finishActivity adjustFocus setFocusedActivity isAttached=true TaskRecord{d952617d0 #2117 A=com.xxx.test U=0 StackId=1 sz=2}
16:23:14.535 3696-13852/? D/InputDispatcher: Focused application set to: xxxx
16:23:14.536 3696-13852/? D/ActivityTrigger: ActivityTrigger activityPauseTrigger
16:23:14.544 30891-30891/? V/AttachActivity: onPause
16:23:14.545 3696-5485/? D/ActivityManager: setAppIconInfo(), x : 0, y : 0, width : 0, height : 0, isHomeItem : false
resumeTopActivityInnerLocked() : #1 prevTask=TaskRecord{d952617d0 #2117 A=com.xxx.test U=0 StackId=1 sz=2} next=ActivityRecord{1da4823d0 u0 com.sec.android.app.camera/.Camera t2117} mFocusedStack=ActivityStack{33a525ad0 stackId=1, 2 tasks}
最终,相机被用户关闭...
16:23:14.634 30891-30891/? V/Camera6: finish
这时,我们收到了MultiScreenManagerService
的更多投诉,现在ActivityManager
希望将com.sec.android.app.launcher
移到前面,我想这是主屏幕... < / p>
16:23:14.637 3696-9814/? W/MultiScreenManagerService: moveTaskBackToDisplayIfNeeded(): root is not base activity
16:23:14.642 3696-9814/? D/ActivityManager: moveToFront() : reason=finishActivity adjustFocus setFocusedActivity isAttached=true TaskRecord{3965df5d0 #2072 A=com.sec.android.app.launcher U=0 StackId=0 sz=1}
16:23:14.642 3696-9814/? W/MultiScreenManagerService: moveTaskBackToDisplayIfNeeded(): root activity or app is null
ActivityManager
的另一条日志中提到了相机的重复完成请求...
16:23:14.663 3696-6002/? W/ActivityManager: Duplicate finish request for ActivityRecord{1da4823d0 u0 com.sec.android.app.camera/.Camera t2117 f}
此时,我假设正在显示主屏幕,但是ActivityManager
的包装上还有其他内容……
16:23:14.715 3696-5436/? D/ActivityManager: resumeTopActivityInnerLocked() : #0 prevTask=TaskRecord{d952617d0 #2117 A=com.xxx.test U=0 StackId=1 sz=2} next=ActivityRecord{eed8739d0 u0 com.sec.android.app.launcher/.activities.LauncherActivity t2072} mFocusedStack=ActivityStack{514789d0 stackId=0, 2 tasks}
applyOptionsLocked(), pendingOptions : null
但无济于事,此后唯一提及我的活动的只是偶然的日志组,例如...
16:23:14.844 3696-3707/? D/PackageManager: getComponentMetadataForIconTray : com.xxx.test.MainActivity does not exist in mServices
getComponentMetadataForIconTray : com.xxx.test.MainActivity does not exist in mProviders
getComponentMetadataForIconTray : com.xxx.test.MainActivity does not exist in mReceivers
16:23:14.846 4439-4439/? I/ApplicationPackageManager: load=com.xxx.test, bg=192-192, dr=192-192, forDefault=true
reset dr=192,192, bg=192,192
因此,问题出在哪里。在相机仍然可见的情况下,系统似乎尝试重新启动我的活动,这使事情搞砸了,但是我仍然不确定到底发生了什么或对此我能做些什么。
有人有什么主意吗?