zl程序教程

您现在的位置是:首页 >  其它

当前栏目

Activity总结

总结 Activity
2023-09-14 08:59:52 时间

 

11.launchMode的属性介绍?及其常用的Intent Flag?

12.onNewIntent()使用Tips?

15.Activit的几个重要属性总结?

====

15.Activit的几个重要属性总结?
1.Activity的affinity(亲和力)
2.Intent几种常见的flags
3.<activity>与task相关属性

launchMode:
taskAffinity:
Activity的task相关属性?
allowTaskReparenting:
alwaysRetainTaskState:
clearTaskOnLaunch:
finishOnTaskLaunch:
documentLaunchMode:


12.onNewIntent()使用Tips?

1. 方法体中需手动调用setIntent(intent),否则之后的getIntent()获取的都是旧的intent对象;
2. 被onNewIntent方式打开的activity,对生命周期的影响.
1. 之前activity是resume状态,onNewIntent()后只会调用onResume()方法
2. 否则按照 `onNewIntent->onRestart->onStart->onResume->.


在IntentActivity中重写下列方法:onCreate onStart onRestart onResume onPause onStop onDestroy onNewIntent
1、其他应用发Intent,执行下列方法:
onCreate
onStart
onResume

2、接收Intent声明:

<activity android:name=".IntentActivity" android:launchMode="singleTask"
  android:label="@string/testname">
  <intent-filter>
  <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="philn"/>
  </intent-filter>
</activity>

3、如果IntentActivity处于任务栈的顶端,也就是说之前打开过的Activity,现在处于onPause、onStop状态的话,其他应用再发送Intent的话,执行顺序为:
onNewIntent,onRestart,onStart,onResume。

在Android应用程序开发的时候,从一个Activity启动另一个Activity并传递一些数据到新的Activity上非常简单,但是当您需要让后台运行的Activity回到前台并传递一些数据可能就会存在一点点小问题。

首先,在默认情况下,当您通过Intent启到一个Activity的时候,就算已经存在一个相同的正在运行的Activity,系统都会创建一个新的Activity实例并显示出来。为了不让Activity实例化多次,我们需要通过在AndroidManifest.xml配置activity的加载方式(launchMode)以实现单任务模式,如下所示:

<activity android:label="@string/app_name" android:launchmode="singleTask"android:name="Activity1"></activity>
launchMode为singleTask的时候,通过Intent启到一个Activity,如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用通常情况下我们处理请求数据的onCreate方法,而是调用onNewIntent方法,如下所示:

protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);//must store the new intent unless getIntent() will return the old one
processExtraData();
}

不要忘记,系统可能会随时杀掉后台运行的 Activity ,如果这一切发生,那么系统就会调用 onCreate 方法,而不调用 onNewIntent 方法,一个好的解决方法就是在 onCreate 和 onNewIntent 方法中调用同一个处理数据的方法,如下所示:

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
processExtraData();
}
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
processExtraData()
}
private void processExtraData(){
Intent intent = getIntent();
//use the data received here
}

二、onNewIntent()的setIntent()和getIntent()
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// setIntent(intent);
int data = getIntent().getIntExtra("HAHA", 0);
// int data = intent.getIntExtra("HAHA", 0);
}

如果没有调用setIntent(intent),则getIntent()获取的数据将不是你所期望的。但是使用intent.getInXxx,貌似可以获得正确的结果。

注意这句话:
Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.
所以最好是调用setIntent(intent),这样在使用getIntent()的时候就不会有问题了。


11.launchMode的属性介绍?及其常用的Intent Flag?


什么是Activity的启动模式(LaunchMode)
启动模式简单地说就是Activity启动时的策略,在AndroidManifest.xml中的标签的android:launchMode属性设置
启动模式有4种,分别为standard、singleTop、singleTask、singleInstance;这四种模式影响了Activity所在的任务栈.

 Intent.setFlag(int flags)方法传递的一个整形的数据,被Android系统设置为了常量:
FLAG_ACTIVITY_NEW_TASK:这个标识会使新启动的Activity独立创建一个Task。
FLAG_ACTIVITY_CLEAR_TOP:这个标识会使新启动的Activity检查是否存在于Task中,如果存在则清除其之上的Activity,使它获得焦点,并不重新实例化一个Activity,一般结合FLAG_ACTIVITY_NEW_TASK一起使用。
FLAG_ACTIVITY_SINGLE_TOP:等同于在LauncherMode属性设置为singleTop。

 

一. Activity的启动模式:
Activity常见四种启动模式是面试常问。
standard:标准启动模式(默认),每次都会启动一个新的activity实例。
singleTop:(栈顶复用)。单独使用模式时,如果Activity实例位于当前任务栈顶,就重用栈顶实例,而不新建,并回调该实例onNewIntent(),否则走新建流程。
singleTask:(栈内复用)。这种模式启动Activity只会存在相应的Activity的taskAffinit任务栈中,同一时刻系统中只会存在一个实例,已存在的实例被再次启动时,会重新唤起该实例,并清理当前Task任务栈该实例之上所有Activity,同时回调onNewIntent()方法。
singleInstance:(单例复用)。这种模式启动的Activity独自占用一个Task任务栈,同一时刻系统中只会存在一个实例,已存在的实例被再次启动时,只会唤起原实例,并回调onNewIntent()。
说明:
1.以上仅适用Activity启动Activity,并且采用都是默认Intent,没有额外添加Flag,否则表现不一致。
2.尤其要注意的是FLAG_ACTIVITY_NEW_TASK的使用,后面从源码中看,依靠FLAG_ACTIVITY_NEW_TASK其实可以分为两派。

1.Intent.FLAG_ACTIVITY_NEW_TASK分析?
是启动模式中最关键的一个Flag,依据该Flag模式可分两类,设置了该属性的与未设置该属性的。
对于非Activity启动的Activity(如Service或者通知中启动的Activity)需显示设置Intent.FLAG_ACTIVITY_NEW_TASK,而singleTask及singleInstance在AMS中被预处理后,隐形设置了Intent.FLAG_ACTIVITY_NEW_TASK,
而启动模式是standard及singletTop的Activity不会被设置Intent.FLAG_ACTIVITY_NEW_TASK,除非通过显示的intent setFlag进行设置。

FLAG_ACTIVITY_NEW_TASK更多关注点是在Task(和taskAffinity有关。没有设置FLAG_ACTIVITY_NEW_TASK情况下,taskAffinity可不考虑)。
大多数下,需要将Activity引入到自己taskAffinity的Task中,Intent.FLAG_ACTIVITY_NEW_TASK的初衷是在Activity目
标taskAffinity的Task中启动,非Activity启动Activity都必须添加Intent.FLAG_ACTIVITY_NEW_TASK才行:

这种情况很有意思,如果目标Activity实例或者Task不存在,则一定会新建Activity,并将目标Task移动到前台,
但是如果Activity存在,却并不一定复用,也不一定可见。
这里假定A是standard的Activity,如果已经有一个A实例,并且所在的堆栈的taskAffinity跟A的taskAffinity一致,这时候要看这个task的根Activity是不是A,如果是A,还要看A的intent是不是跟当前的启动的intent相等,如果都满足,只要将task可见即可。
否则,就需要新建A,并根据A的task栈的存在情况而选择直接入栈还是新建栈。但是,如果Intent想要的启动的Activity的目标堆栈存在,那就将整个堆栈往前迁移,如果位于顶部的Task栈正好是目标Activity的Task栈,那就不做任何处理,连onNewIntent都不会回调,
怎么判断目标Activity的Task栈同找到的栈一致呢?如果找不到目标Task自然会启动Task,如果目标task栈根Activit的intent同新将要启动的Activit相同,就不启动新Activity,否则启动Activity。

2. Intent.FLAG_ACTIVITY_CLEAR_TASK:必须配合FLAG_ACTIVITY_NEW_TASK使用
如果设置FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK,
如果目标task已经存在,将清空已存在的目标Task,否则,新建一个Task栈,之后,新建一个Activity作为根Activity。
Intent.FLAG_ACTIVITY_CLEAR_TASK的优先级最高,基本可以无视所有的配置,包括启动模式及Intent Flag,哪怕是singleInstance也会被finish,并重建。

3. Intent.FLAG_ACTIVITY_CLEAR_TOP
如果没有使用FLAG_ACTIVITY_NEW_TASK,目标是当前Task栈,根据不同的组合产生不同效果。
如果单独使用Intent.FLAG_ACTIVITY_CLEAR_TOP,并且没有设置特殊的launchmode,那么,Google官方示例是:如果ABCD Task中的D采用Intent.FLAG_ACTIVITY_CLEAR_TOP唤起B,这个时候首先会将CD出栈,但是至于B是否会重建,要视情况而定。
如果没有设置FLAG_ACTIVITY_SINGLE_TOP,则会将B finish掉,之后创建新的入栈。如果同一个栈中原来有

如果没有则新建,不会去另一个栈中寻找。

如果同时设置了FLAG_ACTIVITY_SINGLE_TOP,在当前栈已有的情况下就不会重建,而是直接回调B的onNewIntent(),

如果同时使用了FLAG_ACTIVITY_NEW_TASK ,这个时候,目标是Activity自己所属的Task栈,如果在自己的Task中能找到一个Activity实例,则将其上面的及自身清理掉,之后重建。

如果同时在加上FLAG_ACTIVITY_SINGLE_TOP,会更特殊一些,如果topActivity不是目标Activity,就会去目标Task中去找,并唤起

如果topActivity是目标Activity,就直接回调topActivity的onNewIntent,无论topActivity是不是在目标Task中

 

4. Intent.FLAG_ACTIVITY_SINGLE_TOP
Intent.FLAG_ACTIVITY_SINGLE_TOP多用来做辅助作用,跟launchmode中的singleTop作用一样,在Task栈顶有的话,就不新建,栈顶没有的话,就新建,这里的Task可能是目标栈,也可能是当前Task栈,配合FLAG_ACTIVITY_NEW_TASK及FLAG_ACTIVITY_CLEAR_TOP都会有很有意思的效果。

5. 为什么非Activity启动Activity要强制规定使用参数FLAG_ACTIVITY_NEW_TASK
从源码上说,ContextImpl在前期做了检查,如果没添加Intent.FLAG_ACTIVITY_NEW_TASK就抛出异常,
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
...
}

为什么要这么呢?
其实直观很好理解,如果不是在Activity中启动的,那就可以看做不是用户主动的行为,也就说这个界面可能出现在任何APP之上,如果不用Intent.FLAG_ACTIVITY_NEW_TASK将其限制在自己的Task中,那用户可能会认为该Activity是当前可见APP的页面,这是不合理的。

举个例子:我们在听音乐,这个时候如果邮件Service突然要打开一个Activity,如果不用Intent.FLAG_ACTIVITY_NEW_TASK做限制,那用户可能认为这个Activity是属于音乐APP的,因为用户点击返回的时候,可能会回到音乐,而不是邮件(如果邮件之前就有界面)。