深入剖析Android四大组件(一)——Activity生命周期详解(二)

简介: 深入剖析Android四大组件(一)——Activity生命周期详解(二)

2.保存和协调Activity


在Activity切换状态的时候,可能需要保存一些中间状态,比如控件的选择状态等,以便当它重新被显示出来时仍可以恢复到之前推出的状态。


①保存Activity状态

当一个Activity被暂停或者停止的时候,它的状态被保留。因为当它被暂停或者停止的时候,Activity对象仍然驻留在内存中——所有有关它的成员变量和当前状态的信息仍然存在,因此,所有用户导致的Activity的变化就被保存在内存中。而当这个Activity返回到前台时(当它被恢复时),这些变化仍然在内存中。


然而,当系统为恢复内存而销毁一个Activity时,这个Activity对象也就被销毁了,此时系统就不能简单地恢复它并持有它的完整状态。取而代之的是,如果用户再次导航到这里,系统就必须重新创建这个Activity对象,但是用户不知道系统已经销毁了该Activity而现在又重新创建了它,因此,用户可能认为这个Activity就是之前的那个Activity。在这种情况下,我们可以通过实现一个附加的允许保存我们Activity状态信息的回调方法,而将关于Activity状态的重要信息保留下来,然后当系统重新创建这个Activity的时候,再去重新存储它。


保存Activity当前状态信心的回调方法是onSaveInstanceState()。系统在Activity被销毁之前调用此方法,并再传一个Bundle对象。这个Bundle对象可以存储Activity状态(以名称--值对的形式)信息,可以使用像putString()之类的方法。那么,如果系统停止掉Activity进程,并且用户又重新启动该Activity,那么系统进程会将这个Bundle对象传递给onCreate(),这样就可以恢复onSaveInstanceState()中保存的Activity状态了。如果没有为恢复的状态信息,那么传给onCreate()的Bundle对象则是null。


注意:因为保存应用程序状态不是必要的行为,所以不能确保onSaveInstanceState()在Activity被销毁之前调用(例如当用户因为明确关闭而使用BACK键离开该Activity时)。如果这个方法被调用,那么它将总是在onStop()并有可能在onPause()之前调用。


虽然如此,但即使你没有实现onSaveInstanceState()方法,也还是有一些Activity的状态通过Activity类默认实现的onSaveInstanceState()方法恢复。特别是,默认实现会为布局中的每一个视图调用onSaveInstanceState(),允许每一个视图提供它们自己要保存的信息。几乎每一个Android框架中的部件都会适当地实现这个方法。这样一来,当Activity被重新创建的时候,任何一个对于UI可见的变化都被自动保存和恢复。例如,EditText空间保存用户输入的所有文本,CheckBox空间保存它是否被选择。而我们需要做的只是为所有想要保存状态的空间提供一个唯一的ID(借助android:id属性)。


尽管onSaveInstanceState()的默认实现会保存这个Activity UI的有用信息,但是我们可能仍然需要重写它以便保存额外的信息。例如,我们可能需要保存在整个Activity生命周期中变化的成员变量的值。由于默认实现的onSaveInstanceState()帮助保存UI的状态,所以如果重写这个方法是为了保存额外的信息,那么就应该在做任何工作之 前先调用超类的onSaveInstanceState()方法。


注意:因为我们不能保证onSaveInstanceState()会被调用,所以使用它只可以记录Activity的瞬间状态,而不能用来保存持久数据。相反,当用户离开这个Activity时,应该用onPause()保存持久数据(例如那些应该保存到数据库中的数据)。


下图直观的展现了Android是如何保存这些状态的。

71.png


72.png

上图为Android保存这些状态的流程示意图


如果需要恢复保存的状态,应该都知道Activity的生命周期中有一个onCreate()方法中传递了一个Bundle对象,具体恢复的代码如下所示:

@Override
public void onCreate(Bundle saveInstanceState){
super.onCreate(saveInstanceState);
if(saveInstanceState!=null){
//获取你保存的状态信息
}
}


这样一来,当界面被创建的时候,Activity仍然能找到用户最后操作的数据。


需要注意的是,忧郁我们不能保证是否存在保存的状态,因此需要一个判断来鉴别if(saveInstanceState!=null)。


②协调Activity

当一个Activity启动另一个Activity的时候,它们都会经历各自的生命周期的改变。第一个Activity被暂停或停止(如果它仍然可见,就不会被停止)时,另一个Activity被创建,而这些Activity共享的数据被保存到磁盘或别的地方。


生命周期回调的顺序要很好地定义,尤其是当两个Activity在同一个过程中并且一个正在启动另一个的时候。下面给出了Activity A启动Activity B的顺序。


第一,Activity A执行onPause()方法。


第二,Activity B顺序执行onCreate(),onStart(),onResume()方法(Activity现在获得用户焦点)。


第三,如果Activity A在屏幕中不再可见,则它的onStop()方法就会被执行。


这个生命周期回调的序列允许我们管理从一个Activity到另一个Activity转变的信息。例如,假如必须要写数据库,则当第一个Activity停止的时候,那么紧跟着的Activity就可以读取那个停止了的Activity,这样的话,我们就应该在onPause()中而不是在onStop()中写数据库。


3.用实例说话


这个实例非常简单,它包含两个Activity,它们都实现了所有的生命周期回调接口,并且还实现了相关的Activity状态保存与状态恢复的回调方法。此外,我们还可以从一个Activity导航到另一个Activity上。具体的操作步骤如下所示。


①创建一个名为ActivityLife的工程,包名为helloworld.liyuanjing.example.com.activitylife。创建完成后,我们就在原有的基础上添加一个新类SecondActivity,它继承自Activity类。此时Android工程中就拥有两个Java代码文件,它们分别是MainActivity.java和SecondActivity.java。现在,这两个代码都实现生命周期的所有方法,并在各个方法中添加日志。添加日志的方法如下:


Log.e(TAG, message);


②将新增的类SecondActivity声明到AndroidManifest.xml文件中去,这一步非常重要。如果没有这一步,就无法启动SecondActivity。声明代码如下:


<activity android:name=".SecondActivity"></activity>


在AndroidManifest.xml中声明一个Activity有相当多的讲究,这里只做简单配置上去,从而使得我们的Activity可以正常启动,如需深入清单文件可以到http://blog.csdn.net/column/details/androidmanifest.html该专栏下一探究竟。


再者,为了实现从MainActivity上启动SecondActivity,我们需要在默认的布局文件(activity_main)中添加一个按钮。并且实现它的单击事件。在该事件中,启动SecondActivity。修改后的布局代码如下:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<TextView
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
<Button
        android:id="@+id/mybut"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="To SecondActivity"/>
</LinearLayout>


修改后的MainActivity的代码如下:

public class MainActivity extends Activity {
    public static final String TAG="MainActivity";
    private Button mybut=null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e(TAG, "MainActivity::onCreate()");
        this.mybut=(Button)findViewById(R.id.mybut);
        this.mybut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
    }
    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "MainActivity::onStart()");
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "MainActivity::onResume()");
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "MainActivity::onPause()");
    }
    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "MainActivity::onStop()");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "MainActivity::onDestroy()");
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG, "MainActivity::onSaveInstanceState()");
    }
}


SecondActivity的代码如下:

public class SecondActivity extends Activity {
    public static final String TAG="SecondActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "SecondActivity::onCreate()");
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "SecondActivity::onResume()");
    }
    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "SecondActivity::onStart()");
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "SecondActivity::onPause()");
    }
    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "SecondActivity::onStop()");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "SecondActivity::onDestroy()");
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG, "SecondActivity::onSaveInstanceState()");
    }
}


③编译运行工程,注意观察日志。等到应用程序展现出来的时候,就可以观察到如下图所示的日志信息:


出现这样的界面就说明,一个Activity从启动到展示完成经历了从onCreate()到onStart(),在再到onResume的3个阶段。


④单击“导航”按钮,也就是布局文件那个按钮,启动SecondActivity,看看有什么样的日志输出,如下图:


此时,SecondActivity就呈现出来了,而原来的MainActivity则被SecondActivity覆盖掉而不再拥有用户焦点。因此,可得出下面的3个结论。


ⅠMainActivity的onPause()方法被调用。


ⅡSecondActivity将会经历与MainActivity一样的显示过程。


Ⅲ当完成SecondActivity的展现后,MainActivity保存的回调接口(onSaveInstanceState())就被调用。接着还会调用MainActivity的onStop()方法。


⑤按BACK键返回到原来的Activity,看看会发生什么?如下图:


从上图可知,发生了下面4件事情。


ⅠSecondActivity的onPause方法被调用,指示它即将被暂停。


Ⅱ由于MainActivity是曾经被创建的Activity,因此这里只调用了它的onStart()以及onResume()方法来完成Activity的重新展现。


ⅢSecondActivity完成了生命周期而被销毁。在这个过程中,它经历了停止和销毁两个生命周期。这也就意味着当需要它重新显示的时候,只能从重新创建开始了。


Ⅳ如果此次再次按下BACK键,则MainActivity也将被销毁。同样,它的onStop()以及onDestory()也会被依次调用。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
20天前
|
存储 设计模式 数据库
构建高效的安卓应用:探究Android Jetpack架构组件
【4月更文挑战第20天】 在移动开发的世界中,构建一个既高效又可维护的安卓应用是每个开发者追求的目标。随着Android Jetpack的推出,Google为开发者提供了一套高质量的库、工具和指南,以简化应用程序开发流程。本文将深入探讨Jetpack的核心组件之一——架构组件,并展示如何将其应用于实际项目中,以提升应用的响应性和稳定性。我们将通过分析这些组件的设计原则,以及它们如何协同工作,来揭示它们对于构建现代化安卓应用的重要性。
|
1天前
|
XML Java Android开发
利用Bundle实现Android Activity间消息的传递
利用Bundle实现Android Activity间消息的传递
|
1天前
|
Android开发 数据库管理
Android如何在Activity和Service之间传递数据
Android如何在Activity和Service之间传递数据
|
1天前
|
Java 开发工具 Android开发
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
10 4
|
4天前
|
Shell Android开发
Android Activity重写dump方法实现通过adb调试代码
Android Activity重写dump方法实现通过adb调试代码
10 0
|
20天前
|
设计模式 前端开发 数据库
构建高效Android应用:使用Jetpack架构组件实现MVVM模式
【4月更文挑战第21天】 在移动开发领域,构建一个既健壮又易于维护的Android应用是每个开发者的目标。随着项目复杂度的增加,传统的MVP或MVC架构往往难以应对快速变化的市场需求和复杂的业务逻辑。本文将探讨如何利用Android Jetpack中的架构组件来实施MVVM(Model-View-ViewModel)设计模式,旨在提供一个更加模块化、可测试且易于管理的代码结构。通过具体案例分析,我们将展示如何使用LiveData, ViewModel, 和Repository来实现界面与业务逻辑的分离,以及如何利用Room数据库进行持久化存储。最终,你将获得一个响应迅速、可扩展且符合现代软件工
24 0
|
24天前
|
Android开发 开发者
什么是Android Jetpack,它包括哪些组件?
【4月更文挑战第17天】Android Jetpack是Google提供的一套工具集,助力开发者高效、稳定地开发Android应用。它包含架构、UI、行为和基础组件,简化了后台任务、导航和生命周期管理,使开发者能专注于创新。随着不断更新,如CameraX的推出,掌握Jetpack对开发者面试和工作至关重要。
22 0
|
27天前
|
存储 数据库 Android开发
使用Android Jetpack组件加速开发流程
【4月更文挑战第14天】Android Jetpack是为提升开发速度和代码质量而生的组件集合,包括`ViewModel`、`LiveData`、`RecyclerView`、`Room`、`WorkManager`等,它们遵循最新设计原则和最佳实践。例如,`RecyclerView`优化列表显示,`Room`简化数据库操作,`WorkManager`处理后台任务,`ViewModel`和`LiveData`分离业务和UI逻辑。此外,`Navigation`和`Paging`分别优化用户导航和数据加载。通过这些组件,开发者能更高效地构建高性能应用,值得学习和使用。
|
29天前
|
存储 数据库 Android开发
构建高效安卓应用:采用Jetpack架构组件优化用户体验
【4月更文挑战第12天】 在当今快速发展的数字时代,Android 应用程序的流畅性与响应速度对用户满意度至关重要。为提高应用性能并降低维护成本,开发者需寻求先进的技术解决方案。本文将探讨如何利用 Android Jetpack 中的架构组件 — 如 LiveData、ViewModel 和 Room — 来构建高质量的安卓应用。通过具体实施案例分析,我们将展示这些组件如何协同工作以实现数据持久化、界面与逻辑分离,以及确保数据的即时更新,从而优化用户体验并提升应用的可维护性和可测试性。
|
1月前
|
Java Android开发
Android四大组件之Activity组件
Android四大组件之Activity组件