Activity知识总结

在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、别人的总结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • Activity 一、四种形态 运行状态: 当 Activity 处于栈的顶层,可见,并可与用户进行交互 onRe...
    任教主来也阅读 1,622评论 1 10
  • Activity的生命周期 Activity的创建和销毁onCreate(): 执行Activity某些基本设置的...
    Showdy阅读 896评论 0 1
  • 【Android Activity】 什么是 Activity? 四大组件之一,通常一个用户交互界面对应一个 ac...
    Rtia阅读 3,793评论 3 18
  • 转载注明出处:http://www.jianshu.com/p/c2c2ee4eb48a 1. 简介 本篇不针对于...
    王三的猫阿德阅读 2,083评论 2 5
  • 包子的世界 千奇百怪 肉与菜的结合 是不是真的心甘情愿 我倒想知道 当初是谁先出走 舍弃多年的搭档 去寻找自己的归属
    五色浮元子_阅读 161评论 0 0