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函数。开发者可以在该函数中数据化数据源所需的数据库或者其他数据内容。

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

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

时间: 2024-10-12 04:25:00

Android应用常规开发技巧——善用组件生命周期的相关文章

android核心系列--1,组件生命周期

一,进程模型及进程托管 1,一个APP应用是由一个或多个组件构成的,这些组件可以运行在一个进程中,也可以分别运行在多个进程中: 进程的构造和销毁是由系统全权负责的. 2,一个应用进程只有一个应用环境对象,它在第一个应用进程的组件加载之前被构造,在应用进程中最后一个组件结束后销毁. 3,组件可以通过 android:process = ":com.zy.tool.another"  将组件配置到指定的进程中,冒号开头表示这是一个私有进程,只有本应用的组件才能使用该进程. 如果是小写字母开

Android组件生命周期(二)

引言 应用程序组件有一个生命周期——一开始Android实例化他们响应意图,直到结束实例被销毁.在这期间,他们有时候处于激活状态,有时候处于非激活状态:对于活动,对用户有时候可见,有时候不可见.组件生命周期将讨论活动.服务.广播接收者的生命周期——包括在生命周期中他们可能的状态.通知状态改变的方法.及这些状态的组件寄宿的进程被终结和实例被销毁的可能性. 上篇Android组件生命周期(一)讲解了论活动的生命周期及他们可能的状态.通知状态改变的方法.本篇将介绍服务和广播接收者的生命周期: 服务生命

Android组件生命周期(一)

引言 应用程序组件有一个生命周期——一开始Android实例化他们响应意图,直到结束实例被销毁.在这期间,他们有时候处于激活状态,有时候处于非激活状态:对于活动,对用户有时候可见,有时候不可见.组件生命周期将讨论活动.服务.广播接收者的生命周期——包括在生命周期中他们可能的状态.通知状态改变的方法.及这些状态的组件寄宿的进程被终结和实例被销毁的可能性. 本文主要讨论活动的生命周期及他们可能的状态.通知状态改变的方法.分为以下三部分: 1.活动生命周期 2.保存活动状态 3.协调活动 1.活动生命

【转】Android开发之旅:组件生命周期

组件生命周期(一) 引言 应用程序组件有一个生命周期——一开始Android实例化他们响应意图,直到结束实例被销毁.在这期间,他们有时候处于激活状态,有时候处于非激活状态:对于活动,对用户有时候可见,有时候不可见.组件生命周期将讨论活动.服务.广播接收者的生命周期——包括在生命周期中他们可能的状态.通知状态改变的方法.及这些状态的组件寄宿的进程被终结和实例被销毁的可能性. 本文主要讨论活动的生命周期及他们可能的状态.通知状态改变的方法.分为以下三部分: 1.活动生命周期 2.保存活动状态 3.协

React Native组件生命周期

概述 所谓生命周期,就是一个对象从开始生成到最后消亡所经历的状态,理解空间的生命周期,是开发中必须掌握的一个知识点.就像 Android 开发中组件 一样,React Native的组件也有生命周期(Lifecycle). React Native组件的生命周期大致上可以划分为实例化阶段.存在阶段和销毁阶段.我们只有在理解组件生命周期的基础上,才能开发出高性能的app. React Native中组件的生命周期大致可以用以下图表示: 如图: 第一阶段:是组件第一次绘制阶段,如图中的上面虚线框内,

Android中bindService的使用及Service生命周期

Android中有两种主要方式使用Service,通过调用Context的startService方法或调用Context的bindService方法,本文只探讨纯bindService的使用,不涉及任何startService方法调用的情况.如果想了解startService相关的使用,请参见<Android中startService的使用及Service生命周期>. bindService启动服务的特点 相比于用startService启动的Service,bindService启动的服务

React 的组件生命周期

React组件的state或者props发生改变后会导致这个组件重新渲染,此时DOM也会有相应的变化.其中只有Render方法在上一篇博文中提到过,就是DOM渲染时的方法.当然,只有这个方法是不够的哦!,引文在实际的开发中,开发者们需要对组件的各个阶段进行控制,这样就可以高效的进行开发了,为此,就有了React的组件生命周期的概念. 对于一个基本的React组件,可以把每一个React组件的生命周期分为初始化.挂载.更新.卸载四个阶段,在React的这四个阶段中提供了不同的方法,以方便开发者有足

Vue ---- 组件文件分析 组件生命周期钩子 路由 跳转 传参

目录 Vue组件文件微微细剖 Vue组件生命周期钩子 Vue路由 1.touter下的index.js 2.路由重定向 3.路由传参数 补充:全局样式导入 路由跳转 1. router-view标签 2. router-link标签 3.逻辑跳转 this.$router 控制路由跳转 this.$route 控制路由数据 Vue组件文件微微细剖 组件在view 文件中创建 如果需要用到其他小组件可以 在 component文件中创建并导入 view文件下: <template> <di

angular2系列教程(五)Structural directives、再谈组件生命周期

今天,我们要讲的是structural directives和组件生命周期这两个知识点.structural directives顾名思义就是改变dom结构的指令.著名的内建结构指令有 ngIf, ngSwitch and ngFor. 例子 例子是我自己改写的,编写一个structural directives,然后通过这个指令实例化和注销组件,在此同时监视组件生命周期. 源代码 UnlessDirective 这个指令是官网示例中的指令. src/unless.directive.ts im