Android 四大组件丨Activity

Activity 生命周期

onCreate():表示Activity正在被创建,常用来初始化工作,比如调用setContentView加载界面布局资源,初始化Activity所需数据等

onRestart():表示Activity正在重新启动,一般情况下,当前Acitivty从不可见重新变为可见时,OnRestart就会被调用

onStart():表示Activity正在被启动,此时Activity可见但不在前台,还处于后台,无法与用户交互

onResume():表示Activity获得焦点,此时Activity可见且在前台并开始活动,这是与onStart的区别所在

onPause():表示Activity正在停止,此时可做一些存储数据、停止动画等工作,但是不能太耗时,因为这会影响到新Activity的显示,onPause必须先执行完,新Activity的onResume才会执行

onStop():表示Activity即将停止,可以做一些稍微重量级的回收工作,比如注销广播接收器、关闭网络连接等,同样不能太耗时

onDestroy():表示Activity即将被销毁,这是Activity生命周期中的最后一个回调,常做回收工作、资源释放

在这里插入图片描述

建议成对记录:onCreate-onDestroy(创建-销毁)丨onStart-onStop(启动-停止)丨onResume-onPush(可见-隐藏)丨onRestart(重启)


启动 Activity A 跳转 Activity B 再返回 Activity A 会调用哪些方法?如果B是透明主题或者是DialogActivity呢 ?

A 和 B 均为普通Activity时:

启动 Activity A

A onCreate
A onStart
A onResume

跳转 Activity B

A onPause
B onCreate 
B onStart
B onResume
A onStop

返回 Activity A

B onPause
A onRestart
A onStart
A onResume
B onStop
B onDestory

当 B 为 DialogActivity 或 透明主题时时:

启动 Activity A

A onCreate
A onStart
A onResume

跳转 Activity B

A onPause
B onCreate 
B onStart
B onResume
此时 Activity A 并不会 onStop

返回 Activity A

B onPause
此时 Activity 并不会 onRestart、onStart,因为它就没被 onStop,生命周期间的方法都是对应的
A onResume
B onStop
B onDestory

Activity onSaveInstanceState() 的作用及调用场景

onSaveInstanceState() 可在 Activity 被破坏前保存现有布局对象的信息,如屏幕旋转。它一般与 onRestoreInstanceState() 一起使用

onSaveInstanceState 内可通过Bundle对象以 key-value 形式存储当前页面数据,在 onRestoreInstanceState 内可通过相应 key 取出数据

    private static String USER_INPUT_NAME = "user_input_name";
    private static String USER_INPUT_PASD = "user_input_pasd";

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // 保存
        outState.putString(USER_INPUT_NAME, "liyongli");
        outState.putString(USER_INPUT_PASD, "01234567");
        super.onSaveInstanceState(outState);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 检查是否为重新创建被破坏的Activity
        if (savedInstanceState != null) {
            // 输出保存值
            Log.e("==" , savedInstanceState.getString(USER_INPUT_NAME));
            Log.e("==" , savedInstanceState.getString(USER_INPUT_PASD));
        }else{
            Log.e("==" , "正常创建");
        }
    }

Activity 的四种启动模式及应用场景

Standare:默认启动模式,每次都会在虚拟栈顶创建一个实例

SingleTop:检查该 Activity 的实例是否位于栈顶,位于栈顶时复用,非栈顶时创建新实例。应用场景:列表的详情页、状态栏消息通知页

SingleTask:该 Activity 在整个应用中只存在一个实例,启动此 Activity 时会检查虚拟栈中是否存在它的实例,如果存在直接复用,并把当前Activity之上所有实例全部出栈。应用场景:APP Tab 页

SingleInstance:具备 singleTask 模式的所有特性。该模式的 Activity 会启动一个新的任务栈来管理 Activity 实例,并且该实例在整个系统中只有一个。无论从那个任务栈中启动该 Activity,都会是该 Activity 所在的任务栈转移到前台,从而使Activity显示。主要作用是为了在不同程序中共享一个 Activity 实例。应用场景:系统拨打电话页、系统通讯录、地图或导航类APP


Activity Intent Flags 动态设定与静态设定

动态设定 Flags:代码中通过 Intent 的 addFlags 方法指定,Intent.addFlags(Intent.Flag_Activity_***);

Intent intent = new Intent(Context, ****.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

静态设定 Flags:Manifest.xml 文件中配置 android:launchMode="***"

<activity
	android:name="***"  
	···
	···
	android:launchMode="singleInstance">
</activity>

Activity Flags
 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT, // 本flag一般不由应用代码设置,singleTask模式时系统会给你设置。

 Intent.FLAG_ACTIVITY_CLEAR_TASK,  // 本flag能造成在新活动启动前,与新活动关联的任务被清空。也就是说,新活动成为新任务的根,旧的活动都被结束了。本flag只能与FLAG_ACTIVITY_NEW_TASK联合使用

 Intent.FLAG_ACTIVITY_CLEAR_TOP, // 1. 新活动已在当前任务中时,在新活动上面的活动会被关闭,新活动不会重新启动,只会接收new intent。 2. 新活动已在任务最上面时:如果启动模式是"multiple" (默认的),并且没添加FLAG_ACTIVITY_SINGLE_TOP,那么活动会被销毁重新创建;如果启动模式是其他的,或者添加了FLAG_ACTIVITY_SINGLE_TOP,那么只会调用活动的onNewIntent()。 3. 跟FLAG_ACTIVITY_NEW_TASK联合使用效果很好:如果用于启动一个任务中的根活动,会把该任务移到前面并清空至root状态。这特别有用,比如用于从notification manager中启动活动。

 Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, // 已废弃。API 21后用FLAG_ACTIVITY_NEW_DOCUMENT。

 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, // 新活动不会保存在最近启动的活动列表中。

 Intent.FLAG_ACTIVITY_FORWARD_RESULT, // 1. (当前活动由源活动启动)本intent从当前活动启动新活动时,源活动的接收目标会从当前活动转移为新活动。新活动调用setResult的数据会传送给源活动。

 Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY, // 本flag一般不由应用代码设置,活动从历史栈中启动(长按home键)时系统会给你设置。

 Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT, // 本flag只在分屏多窗口模式下使用。新活动会显示在旧活动旁边。本flag只能跟FLAG_ACTIVITY_NEW_TASK联合使用。并且如果你想创建一个已存在活动的新实例,那么要设置FLAG_ACTIVITY_MULTIPLE_TASK。

 Intent.FLAG_ACTIVITY_MULTIPLE_TASK, //  1. 用于创建一个新任务,并启动一个活动放进去;总是跟FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK一起使用;单独用FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK时,会在已存在的任务中寻找匹配的Intent,找不到才会创建一个新任务;使用了本flag不会寻找匹配的Intent,无条件创建一个新任务。2. **用了FLAG_ACTIVITY_NEW_TASK就不要用本flag,除非你启动的是应用的launcher。** 跟FLAG_ACTIVITY_NEW_TASK联合使用能防止把已存在的任务移到前面,会为新活动创建一个新任务,无论已存在的任务中有没有新活动。3. 因为默认安卓系统中没有提供可视化的任务管理,所以你不应该使用本flag,除非给用户提供可以回到其他任务的方法。4. 单独用本flag而不用FLAG_ACTIVITY_NEW_DOCUMENT或者FLAG_ACTIVITY_NEW_TASK是无效的。

 Intent.FLAG_ACTIVITY_NEW_DOCUMENT, //1. 本flag会给启动的活动开一个新的任务记录。使用了本flag或documentLaunchMode属性时,相同活动的多实例会在最近任务列表中产生不同的记录。 2. 使用本flag比使用documentLaunchMode属性更好,因为documentLaunchMode属性会跟活动绑定,而flag只在需要时添加。 3. 注意本flag的默认词义,活动销毁后最近任务列表中的入口不会移除。这跟使用FLAG_ACTIVITY_NEW_TASK不一样,后者活动销毁后入口会马上移除。你可以用FLAG_ACTIVITY_RETAIN_IN_RECENTS改变这个行为。 4. 本flag可以跟FLAG_ACTIVITY_MULTIPLE_TASK联合使用。单独使用时跟manifest活动中定义documentLaunchMode="intoExisting"效果相同,联合使用时跟manifest活动中定义documentLaunchMode="always"效果相同。

 Intent.FLAG_ACTIVITY_NEW_TASK, //  1. 新活动会成为历史栈中的新任务(一组活动)的开始。 2. 通常用于具有"launcher"行为的活动:让用户完成一系列事情,完全独立于之前的活动。 3. 如果新活动已存在于一个为它运行的任务中,那么不会启动,只会把该任务移到屏幕最前。 4. 如果新活动要返回result给启动自己的活动,就不能用这个flag。

 Intent.FLAG_ACTIVITY_NO_ANIMATION, //  1. 本flag会阻止系统展示活动的当前状态到另一个状态之间的转移动画。这并不意味着永远没有动画 -- 如果另一项活动的改变在当前展示的活动启动前发生并且没有使用本flag,那么动画还会展示。当你要进行一系列活动操作,但是用户看到的动画不应该由第一项改变来驱动,而是由下一项。
 
 Intent.FLAG_ACTIVITY_NO_HISTORY, //  1. 新活动不会保留在历史栈中,一旦用户切换到其他页面,新活动会马上销毁。 2. 旧活动的onActivityResult()方法永远不会被触发。

 Intent.FLAG_ACTIVITY_NO_USER_ACTION, // 1. 本flag会阻止当前最前面活动的onUserLeaveHint回调,在它被新启动的活动造成paused状态时。 2. 通常,一个活动在受到用户操作而从前面移走的时候会调用上面的回调。该回调标志着活动生命周期中的一个点,在该点活动会隐藏它想要显示的”直到用户看到“的东西,比如闪烁的LED灯。 3. 如果一个活动曾经由非用户驱动的事件比如来电或闹钟启动,应该在startActivity中添加本flag,以保证暂停时活动知道用户并没有看到通知。

 Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP, //  1. 本intent从当前活动启动新活动时,当前活动不会被视为顶端活动,不管是决定传intent给顶端还是启动新活动。新活动被当做顶端活动使用,假设当前活动立即销毁了。

 Intent.FLAG_ACTIVITY_REORDER_TO_FRONT, //  1. 如果新活动已在任务中,用本flag启动会将它移到任务的历史栈的前面。 2. 如果用了FLAG_ACTIVITY_CLEAR_TOP,本flag就无效。

 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED, // 新活动在新任务中启动或者被放到一个已存在任务的顶端时,会被当做任务的前门来启动。这会导致任何相关性的活动在适当状态下需要拥有这个任务(无论移动活动到它里面或者是移走),或者在需要时简单地重置任务到初始状态。

 Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS, //  1. 默认情况下由FLAG_ACTIVITY_NEW_DOCUMENT创建的新纪录,用户关闭时(按返回键或其他方式结束)它在最近任务中的入口会被移除。如果你想保留入口,就用本flag。 2. 接收的活动可以用autoRemoveFromRecents属性或者调用Activity.finishAndRemoveTask()来覆盖本请求。

 Intent.FLAG_ACTIVITY_SINGLE_TOP, //  1. 新活动已存在历史栈的顶端时就不会重新启动。

 Intent.FLAG_ACTIVITY_TASK_ON_HOME, // 本flag会造成新的启动任务放在当前主页活动任务(如果有的话)的顶端。也就是说,在任务中按返回键总是会回到主页,即使上一个用户看到的活动不是主页。本flag只能与FLAG_ACTIVITY_NEW_TASK联合使用。

此 Flags 目录介绍参考自 rome753:https://www.jianshu.com/p/2bdc16cba04f


Activity 与 Window、View 的关系

Activity 构造时会初始化一个 Window,它的具体实现是 PhoneWindow,每个Activity 对应一个 PhoneWindow

PhoneWindow 内包含 ViewRoot ,它既可以是一个 ViewGroup,也可以是单一View,表示根视图,Activity 通过 setContentView() 将 View 设置在 PhoneWindow 之上

ViewRoot 可以通过addView()、removeView()、updateViewLayout() 实现添加或管理 View

所以 Window / PhoneWindow 是中间人,是桥梁,可以使Activity 和 View 功能解耦,各司其职

当产生触摸、点击事件时,WindowManagerService 会首先接收事件,并回调相应 Activity 提供的 onClickListener、onKeyDown 此类的回调函数处理


Activity 横竖屏切换时的生命周期变化
onPuase
onStop
onDestory
onCreate
onStart
onResume

其实是相当于回收后重建,若需保留一些数据,可通过 onSaveInstanceState()onSaveInstanceState()


启动其他应用的 Activity

在 Activity、Service 和 BroadcastReceiver 均可以启动其它应用的 Activity,

  • 设置Intent的className:
        Intent intent = new Intent(Intent.ACTION_VIEW);
        // 设置包名
        String packageName = "com.example.mylife.anotherapp";
        // 设置类名
        String className = "com.example.mylife.anotherapp.MainActivity";
        intent.setClassName(packageName, className);
        // 或者设置 setComponent
        //intent.setComponent(new ComponentName("com.example.mylife.anotherapp","com.example.mylife.anotherapp.MainActivity"));
        // 添加附带参数
        Bundle bundle = new Bundle();
        bundle.putString("id", "this message is from project B ");
        intent.putExtras(bundle);
        intent.putExtra("token", android.os.Process.myPid());
        startActivityForResult(intent, 1);
  • 隐式Intent的action方式:
    先在 Activity A 中清单文件中设置 intent-filter ; action
        <activity android:name=".B">
            <intent-filter>
                <action android:name="android.intent.action.B"></action>
                <category android:name="android.intent.category.DEFAULT"></category>
            </intent-filter>
        </activity>

在 Activity B (或 Service B)中 Intent action

Intent intent=new Intent("android.intent.action.B");
startActivity(intent);

待更新内容:

Activity 的启动过程原理及分析


本篇将持续更新 Activity 相关知识,一起查漏补缺学个痛快!欢迎点赞留香丨留言鼓励丨指出不足!


在这里插入图片描述

发布了94 篇原创文章 · 获赞 387 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_15609303/article/details/102966812