美文网首页
Activity知识总结

Activity知识总结

作者: 天天one | 来源:发表于2017-12-25 16:32 被阅读10次

    在Android开发中承担的主要角色

    1、App的入口

    你要想用一个app肯定要打开这个app才能使用,主Activity是用户点击这个app之后第一个启动的Activity,这个Activity启动后才能与用户有其他更多的交互,就像是Java程序的入口函数main一样,main函数的执行才能使整个应用跑起来,所以Activity是app的入口。所有的程序都有入口,找到入口才能慢慢的解析整个程序的运行过程。

    2、显示和控制用户的逻辑界面

    所有写给用户使用的程序必然会设计一个好的交互界面,用户在这个界面进行功能选择和使用,在Android系统中,承担起与用户交互的界面是由View来呈现的,但是View的显示是靠Activity来控制。

    所以Activity总是承担着显示用户界面和控制用户操作逻辑的角色。

    生命周期

    程序都是有生命周期的,目前程序在什么生命周期就做该生命周期内的事,别做超越生命周期范围内的事,就像是人生一样,是什么阶段就做什么阶段该做的事,不多做,也别少做。Android系统已经给Activity的生命周期定义很多回调函数,你需要做的就是熟悉这些回调函数,知道在执行这个回调函数的时候Activity的状态和需要在这个状态下进行什么操作。

    public class ExampleActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // The activity is being created.
        }
        @Override
        protected void onStart() {
            super.onStart();
            // The activity is about to become visible.
        }
        @Override
        protected void onResume() {
            super.onResume();
            // The activity has become visible (it is now "resumed").
        }
        @Override
        protected void onPause() {
            super.onPause();
            // Another activity is taking focus (this activity is about to be "paused").
        }
        @Override
        protected void onStop() {
            super.onStop();
            // The activity is no longer visible (it is now "stopped")
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // The activity is about to be destroyed.
        }
    }
    
    

    下图是Google官方的Activity生命周期图,已经非常详尽的说明个Activity生命周期之间的跳转和哪种情况下Activity会被kill掉。


    image

    创建生命周期

    • onCreate:设置Activity要呈现的View,创建Activity需要的资源。
    • onDestory:释放onCreat中创建的资源。

    可见生命周期

    • onStart :Activity 开始变得可见。
    • onStop : Activity 开始变得不可见。onPause中不能进行耗时操作,会影响到新Activity的显示。因为onPause必须执行完,新的Activity的onResume才会执行。
    • onRestart :如果一个Activity在onStop状态,开始变得可见的时候调用。

    可交互生命周期

    • onResume: Activity可以获取焦点并与用户交互。
    • onPause : Activity丢失焦点,不再与用户交互。

    以下是摘自<Google官方文档>:

    image

    名为“是否能事后终止?”的列表示系统是否能在不执行另一行 Activity 代码的情况下,在方法返回后随时终止承载 Activity 的进程。 有三个方法带有“是”标记:(onPause()、onStop() 和 onDestroy())。由于 onPause() 是这三个方法中的第一个,因此 Activity 创建后,onPause() 必定成为最后调用的方法,然后才能终止进程 — 如果系统在紧急情况下必须恢复内存,则可能不会调用 onStop() 和 onDestroy()。因此,您应该使用 onPause() 向存储设备写入至关重要的持久性数据(例如用户编辑)。不过,您应该对 onPause() 调用期间必须保留的信息有所选择,因为该方法中的任何阻止过程都会妨碍向下一个 Activity 的转变并拖慢用户体验。

    在是否能在事后终止?列中标记为“否”的方法可从系统调用它们的一刻起防止承载 Activity 的进程被终止。 因此,在从 onPause() 返回的时间到 onResume() 被调用的时间,系统可以终止 Activity。在 onPause() 被再次调用并返回前,将无法再次终止 Activity。

    注:无法保证系统会在销毁您的 Activity 前调用 onSaveInstanceState(),因为存在不需要保存状态的情况(例如用户使用“返回”按钮离开您的 Activity 时,因为用户的行为是在显式关闭 Activity)。 如果系统调用 onSaveInstanceState(),它会在调用 onStop() 之前,并且可能会在调用 onPause() 之前进行调用。

    注:由于无法保证系统会调用 onSaveInstanceState(),因此您只应利用它来记录 Activity 的瞬态(UI 的状态)— 切勿使用它来存储持久性数据,而应使用 onPause() 在用户离开 Activity 后存储持久性数据(例如应保存到数据库的数据)。

    您只需旋转设备,让屏幕方向发生变化,就能有效地测试您的应用的状态恢复能力。 当屏幕方向变化时,系统会销毁并重建 Activity,以便应用可供新屏幕配置使用的备用资源。 单凭这一理由,您的 Activity 在重建时能否完全恢复其状态就显得非常重要,因为用户在使用应用时经常需要旋转屏幕。

    启动模式

    任务栈:任务是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(即返回栈)中。设备主屏幕是大多数任务的起点。

    standard 标准模式

    每次都会创建新的Activity;

    singleTop 栈顶复用

    当创建的Activity是栈顶时,它的启动类型是singleTop的那么不会新建Activity,而是调用onNewIntent方法,如果不是栈顶则会新建。

    singleTask 栈内复用

    该模式是一种单例模式,即一个栈内只有一个该Activity实例。该模式,可以通过在AndroidManifest文件的Activity中指定该Activity需要加载到那个栈中,即singleTask的Activity可以指定想要加载的目标栈。singleTask和taskAffinity配合使用,指定开启的Activity加入到哪个栈中。

    执行逻辑:

    • 在这种模式下,如果Activity指定的栈不存在,则创建一个栈,并把创建的Activity压入栈内。
    • 如果Activity指定的栈存在,如果其中没有该Activity实例,则会创建Activity并压入栈顶,如果其中有该Activity实例,则把该Activity实例之上的Activity杀死清除出栈,重用并让该Activity实例处在栈顶,然后调用onNewIntent()方法。

    应用场景:

    大多数App的主页。对于大部分应用,当我们在主界面点击回退按钮的时候都是退出应用,那么当我们第一次进入主界面之后,主界面位于栈底,以后不管我们打开了多少个Activity,只要我们再次回到主界面,都应该使用将主界面Activity上所有的Activity移除的方式来让主界面Activity处于栈顶,而不是往栈顶新加一个主界面Activity的实例,通过这种方式能够保证退出应用时所有的Activity都能报销毁。在跨应用Intent传递时,如果系统中不存在singleTask Activity的实例,那么将创建一个新的Task,然后创建SingleTask Activity的实例,将其放入新的Task中。

    singleInstance 单例模式

    作为栈内复用模式(singleTask)的加强版,打开该Activity时,直接创建一个新的任务栈,并创建该Activity实例放入新栈中。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例。

    应用场景:

    呼叫来电界面。这种模式的使用情况比较罕见,在Launcher中可能使用。或者你确定你需要使Activity只有一个实例。建议谨慎使用。

    开发的场景

    1、从A启动B的流程:

    Activity A 和 Activity B

    • 调用A的onPause方法,A失去焦点不可交互;
    • 调用B的onCreate,onStart,onResume,现在B处于前台可交互;
    • 如果A在屏幕上变得不可见,则调用A的onStop;

    2、关于用户配置信息的保存

    要测试应用能否在保持应用状态完好的情况下自行重启,您应该在应用中执行各种任务时调用配置变更(例如,更改屏幕方向)。 您的应用应该能够在不丢失用户数据或状态的情况下随时重启,以便处理如下事件:配置发生变化,或者用户收到来电并在应用进程被销毁很久之后返回到应用。

    但是,您可能会遇到这种情况:重启应用并恢复大量数据不仅成本高昂,而且给用户留下糟糕的使用体验。 在这种情况下,您有两个其他选择:

    在配置变更期间保留对象

    允许 Activity 在配置变更时重启,但是要将有状态对象传递给 Activity 的新实例。利用Fragment实现。当 Android 系统因配置变更而关闭 Activity 时,不会销毁您已标记为要保留的 Activity 的片段。 您可以将此类片段添加到 Activity 以保留有状态的对象。

    • 扩展 Fragment 类并声明对有状态对象的引用。
    • 在创建片段后调用 setRetainInstance(boolean)。
    • 将片段添加到 Activity。
    • 重启 Activity 后,使用 FragmentManager 检索片段。
    public class RetainedFragment extends Fragment {
    
        // data object we want to retain
        private MyDataObject data;
    
        // this method is only called once for this fragment
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // retain this fragment
            setRetainInstance(true);
        }
    
        public void setData(MyDataObject data) {
            this.data = data;
        }
    
        public MyDataObject getData() {
            return data;
        }
    }
    

    注意:尽管您可以存储任何对象,但是切勿传递与 Activity 绑定的对象,例如,Drawable、Adapter、View 或其他任何与 Context 关联的对象。否则,它将泄漏原始 Activity 实例的所有视图和资源。 (泄漏资源意味着应用将继续持有这些资源,但是无法对其进行垃圾回收,因此可能会丢失大量内存。)

    public class MyActivity extends Activity {
    
        private RetainedFragment dataFragment;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            // find the retained fragment on activity restarts
            FragmentManager fm = getFragmentManager();
            dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
    
            // create the fragment and data the first time
            if (dataFragment == null) {
                // add the fragment
                dataFragment = new DataFragment();
                fm.beginTransaction().add(dataFragment, “data”).commit();
                // load the data from the web
                dataFragment.setData(loadMyData());
            }
    
            // the data is available in dataFragment.getData()
            ...
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            // store the data in the fragment
            dataFragment.setData(collectMyLoadedData());
        }
    }
    

    在此示例中,onCreate() 添加了一个片段或恢复了对它的引用。此外,onCreate() 还将有状态的对象存储在片段实例内部。onDestroy() 对所保留的片段实例内的有状态对象进行更新。

    自行处理配置变更

    阻止系统在某些配置变更期间重启 Activity,但要在配置确实发生变化时接收回调,这样,您就能够根据需要手动更新 Activity。利用 android:configChanges 和onConfigurationChanged() 实现。

    注:自行处理配置变更可能导致备用资源的使用更为困难,因为系统不会为您自动应用这些资源。 只能在您必须避免 Activity 因配置变更而重启这一万般无奈的情况下,才考虑采用自行处理配置变更这种方法,而且对于大多数应用并不建议使用此方法。

    3、onSaveInstanceState和 onRestoreInstanceState(Bundle)

    Activity异常情况下(系统资源紧张,横竖屏切换)会被调用用来保存和恢复Activity状态,调用的时序:onSavInstanceState->onStop(If called, this method will occur before onStop(). There are no guarantees about whether it will occur before or after onPause()),onStart->onRestoreInstanceState->onResume.

    其中onCreate和onRestoreInstanceState方法来恢复Activity的状态的区别:onRestoreInstanceState回调则表明其中Bundle对象非空,不用加非空判断。onCreate需要非空判断。建议使用onRestoreInstanceState。

    横竖屏切换的生命周期:onPause()->onSaveInstanceState()-> onStop()->onDestroy()->onCreate()->onStart()->onRestoreInstanceState->onResume()

    可以通过在AndroidManifest文件的Activity中指定如下属性:

    android:configChanges = "orientation| screenSize"
    

    来避免横竖屏切换时,Activity的销毁和重建,会回调了下面的方法:

        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
        }
    

    4、前后台栈交互

    调用SingleTask模式的后台任务栈中的Activity,会把整个栈的Actvity压入当前栈的栈顶。singleTask会具有clearTop特性,会把之上的栈内Activity清除。

    前台栈T1中有Activity A,B,后台栈T2中有 singleTask标志的Activity C,D,当从B启动D时会合并这两个栈成为:A B C D,此时从D开始回退,回退的顺序则是D,C,B,A。

    当从B启动C时会合并为A,B,C,D会被清除。

    Activity的Flags很多,这里介绍集中常用的,用于设定Activity的启动模式。可以在启动Activity时,通过Intent的addFlags()方法设置。

    (1)FLAG_ACTIVITY_NEW_TASK
    其效果与指定Activity为singleTask模式一致。

    (2)FLAG_ACTIVITY_SINGLE_TOP
    其效果与指定Activity为singleTop模式一致。

    (3)FLAG_ACTIVITY_CLEAR_TOP
    具有此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。如果和singleTask模式一起出现,若被启动的Activity已经存在栈中,则清除其之上的Activity,并调用该Activity的onNewIntent方法。如果被启动的Activity采用standard模式,那么该Activity连同之上的所有Activity出栈,然后创建新的Activity实例并压入栈中。

    5、是否所有的数据保存都应该在onPause中执行,并且onPause会一定被执行吗?

    onPause的执行概率会大于onStop,所以在onPause中执行保存最好,但是要快,免得影响程序的执行效率。onPause不是一定会被执行,在关机的时候不会,所以保险起见数据在操作之后最好就保存,而不是非要等到onPause。

    参考:
    1、Android官网
    2、别人的总结

    相关文章

      网友评论

          本文标题:Activity知识总结

          本文链接:https://www.haomeiwen.com/subject/zkglgxtx.html