惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
G
Google Developers Blog
B
Blog
Engineering at Meta
Engineering at Meta
阮一峰的网络日志
阮一峰的网络日志
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 叶小钗
The Cloudflare Blog
The Hacker News
The Hacker News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
雷峰网
雷峰网
F
Fortinet All Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
A
About on SuperTechFans
量子位
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
H
Help Net Security
Help Net Security
Help Net Security
P
Palo Alto Networks Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Troy Hunt's Blog
W
WeLiveSecurity
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
Know Your Adversary
Know Your Adversary
Apple Machine Learning Research
Apple Machine Learning Research
Scott Helme
Scott Helme
N
News | PayPal Newsroom
AWS News Blog
AWS News Blog
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
MongoDB | Blog
MongoDB | Blog
B
Blog RSS Feed
腾讯CDC
J
Java Code Geeks
Microsoft Azure Blog
Microsoft Azure Blog
TaoSecurity Blog
TaoSecurity Blog
GbyAI
GbyAI
Y
Y Combinator Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker

博客园 - 和尚释然

AsyncTask原理 Android 模拟器截图 [原创]Android NDK开发之HelloWorld 附源码 Android NDK开发之环境搭建 [原创]关于Android Service的示例编程 附源码 [原创]Android Camera 开发之实现一 附源码 [原创]Android Camera 开发之前言 [原创]在Eclipse中手工安装SVN Plugin Android开发环境搭建四:新建一台Android Virtual Device Android开发环境搭建三:在Eclipse配置Android SDK Android开发环境搭建二:安装ADT[新版本ADT15.0] Android开发环境搭建一:安装Android JDK Java开发环境配置图解 用Reflector反编译 Mobile Winform程序 Mobile WiFi的开启和关闭代码实现 VS2005/VS2008英文版应用程序无法显示中文字符 深入讲解main()返回值研究 用VisualStudio2008汇编代码 发布MFC ActiveX控件并实现自动更新
[原创]深入了解Activity生命周期 附源码
和尚释然 · 2012-06-28 · via 博客园 - 和尚释然

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

深入了解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状态信息,我会将在后期单独讲解此内容.

源代码下载