Android基础—四大组件之Activity

Activity简介

Activity是基础的应用组件,每个Activity都会获得一个用于绘制用户界面的窗口,用户可与其提供的界面进行交互。

两个Activity之间的导航

Activity启动

调用startActivity()启动Activity。根据目标Activity是否已知,Activity有两种启动方式:

1.显式启动:启动某个已知类名的 Activity。如:

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);复制代码

2.隐式启动:启动未知类名、具有某种功能的Activity。如发邮件:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);复制代码

Activity启动获取返回值

有时,需要从启动的Activity返回结果。这种情况下,需要使用startActivityForResult()启动。要想收到返回结果,需要实现onActivityResult()回调方法。当启动的Activity完成后,会使用IntentonActivityResult()返回结果。

private void pickPicture(){
    Intent intent = new Intent(this,PickPictureActivity.class);
    startActivityForResult(intent,PICK_PICTURE_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK && requestCode == PICK_PICTURE_CODE){
        // 做其他操作
    }
}复制代码
private void setResult(){
    Intent intent = new Intent();
    intent.putExtra("path","/mnt/picture/home.png");
    setResult(PICK_PICTURE_CODE,intent);
}复制代码

Activity之间的协作

当一个activity启动另一个activity时,它们都经历了生命周期的变化,变化顺序如下:

1. Activity A的onPause()方法执行

2. Activity B的onCreate()onStart()onResume()依次执行(Activity B获取焦点)

3. 如果Activity A不再可见的话,Activity A的onStop()方法执行

结束Activity

可以直接调用Activity的finish()方法结束Activity,也可以调用finishActivity(int requestCode)结束之前使用startActivityForResult()启动的Activity

多数情况下,不需要调用这些方法结束 Activity,Android系统会自动管理这些 Activity的生命周期。调用这些方法可能会对用户的预期体验有所影响,所以除非确实不想让用户返回此 Activity实例时才主动结束。

Activity生命周期

通过回调方法管理Activity的生命周期,可以灵活的控制与用户的交互。Activity的生命周期会直接受到其他Activity、任务及返回栈的关联性的影响。


Activity的四种主要状态

1. 运行态:activity位于屏幕最前面(位于栈顶)。

2. 暂停态:activity失去焦点但仍然可见(如一个非全屏或透明的activity位于该activity表面),位于该状态的activity仍处于活跃状态(保存所有状态和变量信息,和窗口管理器关联),但是在系统内存极度紧缺的情况下,可能会被系统杀死。

3. 停止态:activity完全被其他activity掩盖,不可见。仍然保留所有状态和变量信息,但是在系统其他地方需要内存的情况下,可能会被系统杀死。

4. 恢复态:处于暂停态和停止态的activity,系统可能会通过让activity自己调用finish()方法或直接杀死该activity所在进程的方式结束该activity。当重新展示给用户的时候,必须完整地重新启动并恢复之前的状态。

Activity的三种关键循环

1. 完整生命周期:发生在onCreate()onDestroy()之间。一般在onCreate()中做全局状态的设置,在onDestroy()销毁所有保留的资源。如在后台下载网络数据的线程,在onCreate()中创建,在onDestroy()中销毁。

2. 可见生命周期:发生在onStart()onStop()之间。期间,Activity虽然可见,但是不在前台并与用户交互。在这两个方法里,需要维护Activity要展示给用户的资源。如在onStart()中注册监听UI改变的广播,在onStop()中要注销该广播。onStart()和onStop()可能会被调用多次,因为activity或许会不断的可见或隐藏。

3. 前台生命周期:发生在onResume()onPause()之间。期间,activity可见并与用户交互。activity会在这两个状态之间不断切换—例如设备休眠、传输新的Intent—所以这些方法应该非常轻量级,不要处理耗时任务。

Activity状态和进程状态的关系

系统不会直接杀死activity,相反,会杀死该activity所在的进程。系统在需要释放RAM时会杀死进程,被杀死的可能性依赖于进程的状态,而进程的状态依赖于在该进程中运行的activity的状态。


配置改变对activity的影响

如果设备的配置(横竖屏、语言等)发生变化,展现给用户的界面也要被更新以匹配变化。除非特别指定,否则的话配置变化(横竖屏、语言等)必然会导致activity被销毁。

如果activity处于前台或可见状态,一旦onDestroy()被调用就会创建一个新的activity实例,并伴随着之前activityonSaveInstanceState(Bundle)中保存的状态,以便恢复数据。

特殊情况下,配置发生变化,我们不希望重新创建activity实例,可以在Manifest中定义android:configChanges属性,这样的配置变化时,就会调用onConfigurationChanged(Configuration),不会重启启动activity。如下:

android:configChanges="orientation|screenSize“复制代码

activity数据保存和恢复

activity状态数据保存

activity被系统主动销毁时(如内存不足,系统回收资源),系统会调用onSaveInstanceState()onPause()之后,onStop()之前执行)方法以键值对集合的方式保存activityview层的信息(比如EditText的内容、CheckBox的选中状态)。所以必须在onPause()方法后实现onSaveInstanceState()方法:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);


    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}复制代码
注:为了系统能恢复每一个 view的状态, view必须有唯一的id( android:id=""

activity持久数据保存

activity主要处理两种持久数据:共享文件—如数据(使用Content Provider保存在SQLite)和内部状态—如用户偏好(preference)。

对于content provider数据,建议采用“就地编辑”模型,即随时随地保存,不用请求用户确认。一般需要遵守两个规则:

1. 创建新文件时,同时在后台数据库或文件中对该文件进行备份。如写邮件时,只要用户输入数据,就创建备份,便于用户调到其他activity再返回该界面时,内容还在。

2. 当activityonPause()方法调用时,应该把用户的改动及时保存到后台content provider或文件中。

“就地编辑”模型可以避免用户在两个activity之间切换的时候数据丢失,同时也可以使得系统安全的杀死activity(内存不足时,系统会回收资源)。记住,当用户点击“back”时,并不意味着取消输入的内容—它意味着保存当前的内容,取消编辑必须在activity中明确声明,如revert。

activity也保存用户偏好数据,如用户喜好的时钟时间或web浏览器的主页。保存内部数据使用Context.getSharedPreferences(),可以实现多组件(activityservicereceiverprovider)公用,但是不支持多应用之间访问(需要使用content provider)。

Activity状态数据恢复

activity被重新创建时,可以从系统传递给activitybundle中恢复之前保存的数据。onCreate()onRestoreInstanceState()都会收到该bundle,我们可以自由选择在哪个方法中恢复数据。但是由于onCreate()是类创建时必须调用的,所以bundle可能为空(第一次创建该activity),所以在解析bundle之前必须校验非空:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first


    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    ...
}复制代码

如果在onRestoreInstanceState()(在onStart()后调用)中恢复数据,系统只有在bundle中有需要恢复数据的话才会调用该方法;如果没有需要恢复的数据的话不会调用该方法。

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);


    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}复制代码
注:总是调用 onRestoreInstanceState()方法,以便系统能自动恢复 view状态

activity启动模式

taskactivity集合,这些activity被放入返回栈中。启动模式可以定义新Activitytask是如何关联的。可以使用两种方式定义启动模式

1. 使用Manifest文件

2. 使用intent flags

使用manifest文件定义启动模式

使用<activity>元素的launchModel属性定义启动模式,共有四种:

1.standard:默认模式,每一次启动都会创建一个新的activity实例,并和创建者位于同一个Task内。过程如下:


2. singleTop:如果activity不存在或不在栈顶,就创建一个实例;如果activity位于栈顶,就调用onNewIntent()方法。被启动的activity始终和启动activity在同一个Task内。用途:QQ信息提示框,不同时间接收的消息全部显示在一个提示框中。


3. singleTask:系统唯一,但是位于可能包括多个Activity实例的task

应用内启动:如果task中不存在该activity实例,就会创建该activity实例;存在并位于栈顶,调用onNewInten()方法;存在但不位于栈顶,会销毁该实例以上的所有activity,并调用onNewIntent()方法。


应用外启动:如果activity实例已存在一个task中的话,启动后,系统会将这个task切换到前台,并将该activity实例上的activity全部销毁;如果activity实例不存在,会另起一个task(目标activity所在应用的task,如果不存在会创建),并创建activity实例位于栈顶。


4. singleInstance:系统单例模式,位于一个独享的Task中。如果系统中不存在该activity实例,就另起一个task,并创建唯一activity实例位于栈底;如果系统中存在该Activity实例,就直接调用onNewIntent()方法启动实例。

使用Intent flags

启动Activity时,可通过intent.setFlags()设置启动模式;共有三种:

1. FLAG_ACTIVITY_NEW_TASK:创建一个新的Task(如果不指定TaskAffinity,默认放到与包名相同的任务栈中),并把启动的Activity置于栈顶。官网说FLAG_ACTIVITY_NEW_TASKsingleTask模式功能相同,实际测试并非如此:

ActivityA启动ActivityB,ActivityB启动ActivityC,ActivityC再启动ActivityB。以两种模式分别启动ActivityB,结果如下:

FLAG_ACTIVITY_NEW_TASK:,栈的结构(从底到顶):A—B—C—B;

singleTask:栈的结构(从底到顶):A—B

2. FLAG_ACTIVITY_SINGLE_TOP:如果activity位于栈顶,则调用onNewIntent(),而非重建;否则的话重新创建;效果和singleTop相同

3. FLAG_ACTIVITY_CLEAR_TOP:要启动的Activity已经运行在当前的task中,就会销毁该activity上的所有activity,并调用onNewIntent()

taskAffinity

taskAffinity表示Activitytask之间的相关性(默认是应用包名)。默认情况下,同一app中所有activity都具有相同的taskAffinity,即都在同一个task中。但是,activitytaskAffinity可以在manifest文件中<activity>元素的taskAffinity属性中修改。不同app的activity可以共享同一个taskAffinity,同一app中的activity可以具有不同的taskAffinity

taskAffinity在两种情况下发挥作用:

1. 以FLAG_ACTIVITY_NEW_TASK模式启动Activity时:以该模式启动activity时,系统经常会寻求一个不同的task存放activity;但是如果已存在一个task和该activity具有相同taskAffinityactivitytask的默认taskAffinity都是包名),该activity就会被加载到这个task中。

2. allowTaskReparenting属性被设置为true:该属性表示activity能否从启动task中迁移到与其具有相同taskAffinitytask中。常见的如在app中打开浏览器的activityA,当退出app,打开浏览器时,显示的也是activityA。

清除返回栈

如果用户离开一个task太长时间,系统会自动把该task中除了根activity以外的所有activity销毁。用户返回该task时,也只有根activity能被恢复。系统之所以这样做的原因是它认为你已经放弃了该task。通过以下熟悉可以修改系统行为:

1. alwaysRetainTaskState:如果该属性在task的根activity中设置为true的话,task会很长时间保留所有的activity,避免被系统杀死。

2. clearTaskOnLaunch:如果该属性在task的根activity中设置为true的话,一旦离开task,系统会立刻销毁除根activity之外的其他activity

3. finishOnTaskLaunch:该属性和clearTaskOnLaunch类似,但是只作用于单个activity(包括根Activity)。也就是说,如果一个activity设置该属性为true,一旦离开该activity,该activity就会被离开销毁。




转载于:https://juejin.im/post/59dc6ca2f265da432528420a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值