[Android问答] 如何应对Activity进程被杀?

简介:

[Android问答] 如何应对Activity进程被杀?

我们要了解Android手机开发与桌面开发有一个主要不同之处:通常在一部Android手机里同时运行着多个应用(app),每个app对应一个系统进程,当系统需要更多的资源(如内存)而空闲资源不足时,Android系统就会选择杀掉一些“低优先级”的进程以便释放所需资源。

Android系统是如何确定进程优先级的高低的呢?

  • 如果一个app正在与用户交互,那么它所在的进程具有最高优先级;
  • 其次,如果一个app是可见的,例如被一个对话框部分遮挡,它所在进程具有第二高的优先级;
  • 再次,如果app当前是不可见的,也就是被切换到了后台,则它所在进程具有第三高的优先级;这里要补充一点,如果这个后台app启动了一个service,则它比一般的后台app优先级高一些。
  • 最后,如果一个进程里没有包含任何app,这个进程的优先级是最低的。

当系统资源严重不足时,任何一个进程都有可能被杀掉,而当用户想回到一个已经不存在于内存中的Activity时,系统只得新建一个这样的Activity对象并调用它的onCreate()方法进行恢复。所以有时出现这种状况:一个app大部分时间运行很好,偶尔在切换Activity时出现空指针异常导致强制关闭,这多半是在onCreate()方法里使用了已经被重置为空的对象(例如intent里的变量)造成的。即使不出现异常,也会造成表单数据丢失等严重影响使用体验的问题。

要解决这类问题,切不可抱“现在手机内存大,进程一般不会被杀掉”这种侥幸心理,而应该以“应用随时都会被杀掉”的态度来谨慎处理,下面介绍Google建议的方式。

解决方法

由于Activity随时可能需要重建,所以我们要做的事情就是在适当的位置将Activity所需数据进行持久化(从ram复制到rom或sd卡),并在onCreate()方法里利用这些数据恢复现场。

Activity有两类数据需要进行持久化处理:“文档类型数据”和“内部状态类型数据”,前者例如用户正在编辑的表单,后者如用户偏好。

一、为了持久化文档类型的数据,Google建议使用”即时生效”(edit in place)的编辑策略,具体的方式如下:

  • 用户新建文档时,在SQLite数据库(根据需要也可以使用preference)里也立即新建一条记录。(与此相对的方式是:为用户提供一个“保存”按钮,只有当用户按下按钮时才将文档保存到数据库。)
  • 当用户离开当前Activity时,onPause()方法会被触发,在这个方法里将当前正在编辑的文档持久化到数据库。这样一来,如果用户是从这个Activity切换到另一个相关Activity,仍然可以看到刚刚保存的内容。

这种方式可以最大限度避免数据丢失,只要onPause()方法被触发执行,即使Activity所在进程被系统kill掉也不会造成数据丢失。唯一要注意的是,界面上最好能提供一个“取消”按钮或菜单,以便让用户可以选择不保存对文档的更改。

二、为了持久化内部状态类型的数据,可以在onPause()里使用Activity#getPreferences(int)方法,这个方法返回SharedPreferences类型的对象,利用它可以记录用户对这个Activity的偏好信息。例如一个日历应用,用户可以选择显示为周视图或月视图,这样的信息作为内部状态记录到SharedPreferences对象以后,下次再打开这个Activity时就可以按用户上次的选择来显示日历了。

以下代码来自官方文档,演示了如何持久化并恢复一个Activity的当前显示模式:

 public class CalendarActivity extends Activity {
     ...

     static final int DAY_VIEW_MODE = 0;
     static final int WEEK_VIEW_MODE = 1;

     private SharedPreferences mPrefs;
     private int mCurViewMode;

     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         //取回之前持久化的日历显示模式
         SharedPreferences mPrefs = getSharedPreferences();
         mCurViewMode = mPrefs.getInt("view_mode", DAY_VIEW_MODE);
     }

     protected void onPause() {
         super.onPause();

         //持久化日历显示模式 
         SharedPreferences.Editor ed = mPrefs.edit();
         ed.putInt("view_mode", mCurViewMode);
         ed.commit();
     }
 }

是有点麻烦,但为了能让app稳定运行也值了。

有些同学要问了,为什么是在onPause()里持久化而不是在onSaveInstanceState()里?官方文档有下面一段话简要解释了原因,即前者比后者更可靠,因为onSaveInstanceState()不属于Activity生命周期的一部分。——既然如此,我想不出onSaveInstanceState()还有什么其他用途了,大家干脆忘了它吧,还有onRestoreInstanceState()。

Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the latter is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation.

注1:关于上面这段话,网上存有一些争议,我个人还是比较倾向在onPause()里做持久化——既可靠又好记,唯一的缺点是调用次数稍多。

注2:从Android 3.0(HoneyComb)版本开始,Activity进程在被系统杀掉之前,将保证onStop()方法先执行完成,因此如果我们开发的应用只运行在3.0以上,可以把持久化工作放在onStop()里以减少持久化的次数。

最佳实践

不要抱侥幸心理,你的Activity随时可能被销毁。

解决方法:在onPause()里持久化Activity数据,在onCreate()里恢复现场

参考资料:

ActivitySaving Activity state in Android

本文转自博客园八进制的博客,原文链接:[Android问答] 如何应对Activity进程被杀?,如需转载请自行联系原博主。


相关文章
|
21天前
|
API Android开发
判断前台 Activity 是否属于本进程
一种判断前台 Activity 是否属于本进程的方法。
25 10
|
24天前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
70 6
|
25天前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
25 3
|
25天前
|
缓存 前端开发 Android开发
Android实战之如何截取Activity或者Fragment的内容?
本文首发于公众号“AntDream”,介绍了如何在Android中截取Activity或Fragment的屏幕内容并保存为图片。包括截取整个Activity、特定控件或区域的方法,以及处理包含RecyclerView的复杂情况。
18 3
|
25天前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
17 0
|
2月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
讲解Activity的启动流程了,Activity的启动流程相对复杂一下,涉及到了Activity中的生命周期方法,涉及到了Android体系的CS模式,涉及到了Android中进程通讯Binder机制等等, 首先介绍一下Activity,这里引用一下Android guide中对Activity的介绍:
49 4
|
3月前
|
XML Android开发 数据格式
android中两个Activity同时设定了intent-filter的category为android.intent.category.LAUNCHER,会发生什么情况?
本文通过案例分析了在Android中当两个Activity都设置了`android.intent.category.LAUNCHER`类别时,会导致它们同时在应用启动器的"所有应用"页面显示为不同的启动入口。
77 2
android中两个Activity同时设定了intent-filter的category为android.intent.category.LAUNCHER,会发生什么情况?
|
2月前
|
Java Android开发 数据安全/隐私保护
Android中多进程通信有几种方式?需要注意哪些问题?
本文介绍了Android中的多进程通信(IPC),探讨了IPC的重要性及其实现方式,如Intent、Binder、AIDL等,并通过一个使用Binder机制的示例详细说明了其实现过程。
308 4
|
2月前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
51 0
|
3月前
|
API Android开发
Android P 性能优化:创建APP进程白名单,杀死白名单之外的进程
本文介绍了在Android P系统中通过创建应用进程白名单并杀死白名单之外的进程来优化性能的方法,包括设置权限、获取运行中的APP列表、配置白名单以及在应用启动时杀死非白名单进程的代码实现。
62 1

相关实验场景

更多