Android应用常规开发技巧——善用组件生命周期

数据管理

对于仅仅读数据。一种经常使用的管理模式是在onCreate函数中进行数据的载入,直到组件的onDestory函数被调用时在进行释放。

    // 缓存仅仅读的数据
private Object readOnlyData; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 读取数据到内存
readOnlyData = readOnlyData();
} private Object readOnlyData() {
return null ;
} @Override
protected void onDestroy() {
super.onDestroy();
// 将数据置空,加速回收
readOnlyData = null ;
}

假设数据支持读写操作。则须要在onResume或者onCreate中进行读取,而在onPause中实现存储。

由于当onPause函数被调用后,该界面组件就处于可回收的状态。当资源紧张时,系统会强行销毁组件对象。

对象中全部未持久化的改动就会丢失。

对于读写数据处理的模型示比例如以下:

    // 缓存可读写的数据
private Object data; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 读取数据到内存
data = readData();
} @Override
protected void onResume() {
super.onResume();
data = readData();
} private Object readData() {
// TODO 读取数据
return null ;
} private void writeData(Object data) {
// TODO 写入数据
} @Override
protected void onPause() {
super.onPause();
writeData( data);
} @Override
protected void onDestroy() {
super.onDestroy();
// 将数据置空。加速回收
data = null ;
}

状态管理

当系统将界面组件切离前台状态(即onPause函数调用前),会先行调用onSavaInstanceState函数。在该函数中,开发人员能够讲组件中的状态数据写入參数的outState对象中。outState的对象类型是Bundle,他是通过键值对的方式进行数据的存储。

onCreate —— 假设含有state数据。则先调用onRestoreInstanceState。

onRestoreInstanceState —— 组件进入前台状态前,先调用恢复数据。

onSaveInstanceState —— 组件离开前台状态,先调用状态保存数据。在调用onPause。

假设用户是主动离开前台状态。则不会触发该状态。

    boolean       needSaveDraft = true;

    // 假设是非主动离开时。则会调用onSaveInstanceState
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// 先保存改动状态。用于恢复启动时恢复该信息
outState.putBoolean( "NEED_SAVE_DRAFT", needSaveDraft );
// 表示在被动退出时无需保存
needSaveDraft = false ;
} @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
needSaveDraft = savedInstanceState.getBoolean("NEED_SAVE_DRAFT" );
}
} @Override
protected void onPause() {
super.onPause();
// 假设不是被动推动,则询问用户
if (needSaveDraft ) {
showAskSaveDraftDialog();
}
} private void showAskSaveDraftDialog() {
// TODO Auto-generated method stub }

当前onSaveInstanceState函数调用完毕后,存储状态信息的outState对象中的数据就由系统进程代为保管,不论该应用进程是否被系统回收,这些数据都不会丢失。

假设savedInstanceState为空,说明这是一次全新的构造。反之则说明这是一次恢复性的构造。

界面组件能够利用该參数中的信息将界面状态恢复到系统回收前的状态。

区分是恢复性构造还是全新的狗仔,是开发中须要妥善处理的细节。假设是全新的构造,界面组件中须要分析调用发送的Intent对象,控制业务流程。而假设是恢复性构造,则须要将上次缓存的信息一一恢复。

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
needSaveDraft = savedInstanceState.getBoolean("NEED_SAVE_DRAFT" );
}
else {
// TODO 解析Intent对象传入的參数或者Action
// Intent intent = getIntent();
// intent.getBundleExtra("");
}
}

为了减少开发人员的负担。Android中的大部分的系统控件都实现了状态缓存的逻辑。在onSaveInstanceState函数调用前,界面组件会遍历整个控件树,将各个控件保存下来。等到onRestoreInstanceState函数被调用时在进行恢复。

假设系统内置的控件状态缓存逻辑不符合开发人员的需求,开发人员能够调用View.setSaveEnabled函数关闭相应控件对象的自己主动缓存。在onSaveInstanceState函数中自行管理控件的状态。

用于状态管理的onSaveInstanceState 和 onRestoreInstanceState并不属于主要的生命周期函数,可是状态管理的操作还是和组件的生命周期有必定的联系,开发人员相同须要妥善利用好这些函数,处理由于生命周期变更引起的变化。

注冊管理

界面组件在于用户交互的过程中有时候须要随着系统状态的变化及时的更新信息。比方地址信息。

界面组件能够通过监听相关的事件信息来捕获这些变化。假设所监听的事件的变化。仅当组件在前台状态时才须要生效(比方广播事件的监听。地理位置的变更等),则须要早onResume中注冊,在onPause中注销。

   LocationManager             mLocationManager;
LocationListener mLocationListener; @Override
protected void onResume() {
super.onResume();
mLocationManager.requestLocationUpdates(provider, minTime, minDistance, listener );
} @Override
protected void onPause() {
super.onPause();
mLocationManager.removeUpdates(mLocationListener );
}

线程管理

在应用开发中。网络通信、数据操作、复杂计算等都须要耗费大量的时间,因此应用通常须要採用多线程的设计模式,在后台线程中运行此类耗时的操作。

Android的组件生命周期,是一个典型的同步处理逻辑。

对于多线程架构没有提供良好的支持模型。这个须要开发人员依据自己的需求,充分利用好组件的生命周期,合理的安排线程的构造及销毁。

假设线程的生命周期和该组件的生命周期紧密联系,就须要在界面组件生命周期中管理该线程,一旦线程被界面组件构造出来,就须要在onDestory中明白终止该线程,回收其线程空间。否则,将导致线程资源泄漏。

可是仅在onDestory回收线程依旧不够完美,由于在资源紧张的情况下,系统会强行回收组件。此时组件的onDestory函数可能并没有调用。从而导致线程资源泄漏。

一个更好的线程管理方案,是将线程的句柄信息当做界面组件的状态信息缓存下来。

假设系统强行回收该对象组件,则须要在组件再次被构造时,依据缓存的线程句柄找到该线程。从而避免线程泄露。

static final String THREAD_WORKER_ID = “thread_id”;

Thread workerThread;

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
long threadId = savedInstanceState.getLong(THREAD_WORKER_ID);
workerThread = findThreadById(threadId);
}
else {
// TODO 创建新的线程
}
} private Thread findThreadById( long id) {
// 完好依据线程id。找到该线程 的过程 http://bao231.iteye.com/blog/1917616?utm_source=tuicool return null ;
} @Override
protected void onDestroy() {
super.onDestroy();
if (workerThread != null) {
workerThread.interrupt();
workerThread = null ;
}
}

服务组件的生命周期

服务的使用方式可分为两种,各自是调用服务和绑定服务。这两种不同的使用方式下,生命周期稍微有不同。

但不论在何种使用模式下,组件的生命周期都是从onCreate中開始,至onDestory中结束。

由于服务组件开发中,能够选择在onCreate中做数据载入等初始化工作,而在onDestory中做数据销毁。线程终止等清理工作。

在绑定模式下。onBind函数被调用时,说明服务以及被前台界面组件绑定。服务组件应依据调用者传递的Intent对象。在该函数内载入资源,构建通信对象。等待绑定者的调用。当界面组件完毕相关操作时。需会解除与服务组件的绑定。此时,onUnBind函数会被调用,能够在该函数中做一些统计和资源清理工作。

被绑定服务组件的进程状态。与绑定该服务的界面组件密切相关。

假设绑定组件为前台界面组件。则改服务所处的进程即为前台进程。反之也相同。

Android系统不会轻易回收前台进程或者可视进程。所以出于绑定状态的组件通常也不会被强制停止。对于开发人员而言。绑定服务后一定不要忘记选择在合适的时机接触绑定。否则将使服务组件停留在前台或可视状态无法回收。从而浪费系统资源。

在调用模式,当服务组件运行onStartCommand函数时。服务所在的进程为前台进程,拥有最高的优先级。当onStartCommand函数运行完毕后。假设没有显示的调用stopSelf等相关函数来停止服务组件。那么该服务组件将会成为后台组件继续提供服务。直至调用stopSelf函数停止。或者等待系统强行回收。

onStartCommand函数中添加三个返回值和控制參数,用于指定后台服务组件的运行方式。当中最重要的返回值有三个:

START_STICKY —— 系统会对该服务组件负责究竟。在强行回收该组件后后,在资源宽裕的时候还会调用onStartCommand函数又一次启动该服务。直到调用stopSelf函数。对于开发人员而言,编写返回值为START_STRICKY,一定要在合适的时机调用stopSelf函数主动关闭服务,否则会无限期的消耗系统资源。

START_NOT_SRICKY —— 说明系统能够无条件的回收该组件,而无需关注服务是否完毕,也不须要负责服务的又一次启动。

START_REDELIVER_INTENT —— 则意味着须要保障该服务组件能够完整的处理完每个Intent对象。

触发器组件的生命周期:

触发器的生命周期是最短暂的。其整个生命周期就是构造触发器对象,然后运行onReceive函数。

对于运行完onReceive函数,系统会马上出发销毁触发器的组件对象,回收其占用的资源。

生命周期内,onReceive函数内部不能够处理耗时任务。

数据源组件的生命周期

理论上来说,数据源组件没有所谓的生命周期,因此数据源组件的状态不作为进程优先级的推断依据。所以系统在回收进程资源时,并不会将数据源的销毁事件告知开发人员。

但Android会在构造数据源组件时调用onCreate函数。开发人员能够在该函数中数据化数据源所需的数据库或者其它数据内容。

由此可知,在数据源组件中部署延迟写入等写优化策略是不合适。由于数据源组件可能会被系统静默回收,从而导致未持久化的写入数据丢失。所以在数据源组件的实现中,写优化策略应该交由上层调用去实现,或者下层数据存储者去处理。

一旦数据源组件构造出来,就会保持长期运行的状态直至其所在的进程被系统回收。所以不要再数据源组件中缓存过多的数据,以免占用内存空间。

观察者事件:

通常假设在onResume与onPause中,接收到观察者事件能够安全的运行兴许观察者事项。

尽量确保组件的观察者事件仅仅处理当前界面处于前台状态下的事物,而可视状态甚至后台状态下的事物,不能够依赖观察者事件来处理。

由于观察者事件并不能确保在组件生命之间可达。

观察者事件仅仅应该在组件可见的生命周期内运行监听,其余的数据更新须要依赖于组件的生命周期方法。

比方onStart,onStop,onResume,onPause等。过度依赖于观察者事件,将导致将必要的功能与观察者事件耦合。

观察者事件的add和remove须要成对出现。否则会引发内存泄露。

上一篇:android核心系列--1,组件生命周期


下一篇:vue 源码详解(二): 组件生命周期初始化、事件系统初始化