代码改变世界

[原创]深入了解Activity生命周期 附源码

2012-06-28 22:42  和尚释然  阅读(2048)  评论(2编辑  收藏  举报

深入了解Activity生命周期


         正确理解Activity生命周期对我们开发灵活的Android应用程序有很大的帮助.大家是否有遇到过这样的情况:当在设备屏幕旋转时,用户一些输入的信息将会丢失.如果正确理解了Activity的生命周期,对于这个问题应该很好解决.其实当屏幕在旋转时,Activity已经销毁后又重新创建了.所以在呈现Activity时那些信息就丢失了.

 

一.管理Activity的生命周期

Activity的三个主要状态

         Android系统中,Activity实际上存在于三种状态:Resumed,Paused,Stopped.

Resumed状态

         Running状态,显示在屏幕上同时有用户输入操作焦点.

Paused状态

         失去用户输入操作焦点,但对于用户还是可见的.覆盖Activity可能是透明或者部分覆盖.

Stopped状态

         完全被其他Activity覆盖.即进入后台.

 

Activity状态图

 

Activity处理Stopped,Paused状态时,Activity都是出于存活状态”.也就是Activity对象存活在系统内存中,它继续维护着Activity的所有状态和成员信息.唯一的区别是:

Stopped状态下Activity对象已经与”Window Manager”失去关联.此时对用户来说已经是不可见了.如果某处需要内存时系统会轻易的杀死该Activity.

Paused状态下Activity对象继续与”Window Manager”保持关联.但是系统如果出现内存不足时,系统会杀死该Activity.

 

Activity的完整生命周期

大家可以通过下图了解到一个Activity从创建到销毁的整个生命流程.通过实现相应的回调方法来保存和恢复一些类似状态,字符串等信息.

矩形代表你可以在代码中重载的方法,例如:onCreate()就是对应我们MainActivity代码中的onCreate方法.

 

@Override

    public void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

 

       wordList = new ArrayList<String>();

       adapter = new ArrayAdapter<String>(this,

              android.R.layout.simple_list_item_1, android.R.id.text1,

              wordList);

       setListAdapter(adapter);

       doBindService();

    }

  

二.保存Activity的状态

在上述管理Activity的生命周期小节中我们了解到,ActivityPaused,Stopped状态时Activity对象的相关状态和信息是继续保存在系统内存中.所以当重新回到Resumed状态时,可以获取到切换前Activity对象的相关状态和信息.

然而,为了空出更多内存系统将销毁Activity对象.这样系统将无法恢复该Activity对象,取而代之,系统必须重建Activity对象.Android提供”onSaveInstancestate()”回调方法来让开发者手工保存一些状态信息,同时方法会传递一个Bundle对象.所以我们可以将需要保存的信息保存到Bundle对象,然后当系统重现Activity时从onCreate()方法取得Bundle对象来获取当初保存的状态信息.

那么Android是在什么时候来调用”onSaveInstanceState()”方法呢?我们先来看下图.

上图展示了两种途径来返回用户界面,左边的图展示了Activity进入Stopped状态,然后重返到Running状态.这种情况下无需保存状态信息,因为此时Activity对象还保存在内存中并没有被销毁.

右边的图展示了Activity进入Stoppecd状态后,由于其他应用程序需要内存,系统将此Activity销毁,这种情况下就需要保存状态信息.直到重现Activity时再恢复之前保存的信息.

有一点需要注意,”onSaveInstanceState()”方法不是任何时候都会被调用的,当用户在按回退键(Back),系统不会调用此方法.Back键的调用顺序是

”onPause()”-> ”onStop()”->”onDestroy()”.这种情况就需要做一些特殊处理,例如将信息保存在静态变量中.大家可以在我的代码基础上作一下修改即可实现.

使用”onSaveInstanceState()”方法只能通过Bundle对象来保存一些简单的信息,如果需要保存更多的,更复杂的数据结构,这种方法就显得不太合适了可以使用的另外一种方法是使用”onRetainNonConfigurationInstance()”回调方法.当一个Activity因为配置更改(例如屏幕方向的改变)Activity销毁的时候,Android系统将调用这个方法.该回调方法的使用我们将在代码实例中演示如何使用?

三.代码实例

最后我们以一个具体示例来总结我们上述所讲的知识.示例是一个简单的登录窗口,在用户输入相关用户信息后,退回到主页或者运行其他程序后,重返到该示例界面时恢复用户之前的输入信息.

界面设计

我们在恢复用户名信息时采用”onSaveInstanceState()”方法,在恢复密码信息时采用” onRetainNonConfigurationInstance()”方法.

主要代码: 

public class MainActivity extends Activity {

   

    private EditText etName, etPwd;

   

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        etName = (EditText)this.findViewById(R.id.etUserName);       

        if (savedInstanceState != null)

        etName.setText(savedInstanceState.getString("UserName"));

       

        etPwd = (EditText)this.findViewById(R.id.etPwd);

        if (null != getLastNonConfigurationInstance())

        etPwd.setText(getLastNonConfigurationInstance().toString());   

    }

 

    @Override

    protected void onPause() {

       // TODO Auto-generated method stub

       super.onPause();

    }

 

    @Override

    public Object onRetainNonConfigurationInstance() {

       etName = (EditText)this.findViewById(R.id.etUserName);

       return etName.getText().toString();

    }

 

    @Override

    protected void onSaveInstanceState(Bundle outState) {

       etName = (EditText)this.findViewById(R.id.etUserName);

       String strUName;

       if (null != etName) {

           strUName = etName.getText().toString();

           outState.putString("UserName", strUName);

       }

       super.onSaveInstanceState(outState);

    }

}

希望本文能对广大Android的童鞋们有所帮助,相信理解了Activity的生命周期,对大家今后的开发工作有很大的帮助.如有不足之处,请指出并见谅.关于如何保存Activity状态信息,我会将在后期单独讲解此内容.

 

源代码下载