1.知识补充
任务是用户在执行某项工作时与之互动的一系列 Activity 的集合。Activity的管理是采用任务栈的形式。任务栈采用“后进先出”的栈结构。每按一次Back键,就有一个Activity出栈 。
2.启动模式的设置
启动模式有两种设置方式。
<1> 通过 AndroidMainifest 设置
android:launchMode可取值以及含义
(1) standard:标准模式
默认值。系统在启动该 Activity 的任务中创建 Activity 的新实例,即启动Activity和目标Activity在同一Activity栈中。Activity 可以多次实例化,一个任务可以拥有多个实例。
(2) singleTop:栈顶复用模式
如果当前任务的顶部已存在 目标Activity 的实例,则系统会通过调用其 onNewIntent()
方法来将 intent 转送给该实例,而不是创建 Activity 的新实例。Activity 可以多次实例化,一个任务可以拥有多个实例(但前提是返回堆栈顶部的 Activity 不是该 Activity 的现有实例)。
例如,假设任务的返回堆栈包含根 Activity A 以及 Activity B、C 和位于顶部的 D(堆栈为 A-B-C-D;D 位于顶部)。收到以 D 类型 Activity 为目标的 intent。如果 D 采用默认的 "standard"
启动模式,则会启动该类的新实例,并且堆栈将变为 A-B-C-D-D。但是,如果 D 的启动模式为 "singleTop"
,则 D 的现有实例会通过onNewIntent()
方法接收 intent,因为它位于堆栈顶部,堆栈仍为 A-B-C-D。但是,如果收到以 B 类型 Activity 为目标的 intent,则会在堆栈中添加 B 的新实例,并且堆栈将变为 A-B-C-D-B,即使其启动模式为 "singleTop"
也是如此。
(3) singleTask:栈内复用模式
系统会创建新任务,并实例化目标Activity。但是,如果任务中已存在该 Activity 的实例,则系统会通过调用其onNewIntent()
方法将 intent 转送到该现有实例,而不是创建新实例。Activity 一次只能有一个实例存在。
(4) singleInstance:单例模式。
与 "singleTask"
相似,唯一不同的是系统不会将任何其他 Activity 启动到包含该实例的任务中。该 Activity 始终是其任务唯一的成员;由该 Activity 启动的任何 Activity 都会在其他的任务中打开。
补充:在AndroidMainifest设置launchMode时,几个配套使用的属性
<2> 通过 Intent 设置标志位
Intent intent=new Intent(SplashActivity.this, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
addFlags可取值以及含义
(1) FLAG_ACTIVITY_NEW_TASK
在新任务中启动 Activity。如果您现在启动的 Activity 已经有任务在运行,则系统会将该任务转到前台并恢复其最后的状态,而 Activity 将在onNewIntent()
方法中收到新的 intent。
这与上一节中介绍的launchMode属性
"singleTask"
产生的行为相同。
(2) FLAG_ACTIVITY_CLEAR_TOP
如果要启动的 Activity 已经在当前任务中运行,则不会启动该 Activity 的新实例,而是会销毁位于它之上的所有其他 Activity,并通过onNewIntent()
方法将此 intent 传送给它的已恢复实例(现在位于堆栈顶部)。
launchMode属性没有可产生此行为的值。
FLAG_ACTIVITY_CLEAR_TOP
最常与 FLAG_ACTIVITY_NEW_TASK
结合使用。将这两个标记结合使用,可以查找其他任务中的现有 Activity,并将其置于能够响应 intent 的位置。
(3) FLAG_ACTIVITY_SINGLE_TOP
如果要启动的 Activity 是当前 Activity(即位于返回堆栈顶部的 Activity),则现有实例会收到对onNewIntent()
方法的调用,而不会创建 Activity 的新实例。
这与上一节中介绍的 "singleTop"
launchMode值产生的行为相同。
<3> 二者设置的区别
有些启动模式可通过清单文件定义,但不能通过 intent 标记定义,同样,有些启动模式可通过 intent 标记定义,却不能在清单中定义。
3.亲和性
<1> 简介
亲和性 表示 Activity 倾向于属于哪个任务。默认情况下,同一应用中的所有 Activity 彼此具有亲和性。因此,在默认情况下,同一应用中的所有 Activity 都倾向于位于同一任务。
不过,也可以修改 Activity 的默认亲和性。在不同应用中定义的 Activity 可以具有相同的亲和性,或者在同一应用中定义的 Activity 也可以被指定不同的任务亲和性。
您可以使用
taskAffinity 属性采用字符串值,该值必须不同于
<2> 作用
亲和性可在两种情况下发挥作用:
(1) 当启动 Activity 的 intent 包含 FLAG_ACTIVITY_NEW_TASK 标记时。
默认情况下,新 Activity 会启动到调用 startActivity() 的 Activity 的任务中。它会被推送到调用方 Activity 所在的返回堆栈中。但是,如果传递给 startActivity() 的 intent 包含 FLAG_ACTIVITY_NEW_TASK 标记,则系统会寻找其他任务来容纳新 Activity。通常会是一个新任务,但也可能不是。如果已存在与新 Activity 具有相同亲和性的现有任务,则会将 Activity 启动到该任务中。如果不存在,则会启动一个新任务。
如果此标记导致 Activity 启动一个新任务,而用户按下主屏幕按钮离开该任务,则必须为用户提供某种方式来返回到该任务。有些实体(例如通知管理器)总是在外部任务中启动 Activity,而不在它们自己的任务中启动,因此它们总是将 FLAG_ACTIVITY_NEW_TASK 添加到传递给 startActivity() 的 intent 中。如果您的 Activity 可由外部实体调用,而该实体可能使用此标记,请注意用户可以通过一种独立的方式返回到所启动的任务,例如使用启动器图标(任务的根 Activity 具有一个 CATEGORY_LAUNCHER intent 过滤器;请参阅下面的启动任务部分)。
(2) 当 Activity 的 allowTaskReparenting 属性设为 "true" 时。
在这种情况下,一旦和 Activity 有亲和性的任务进入前台运行,Activity 就可从其启动的任务转移到该任务。
举例来说,假设一款旅行应用中定义了一个报告特定城市天气状况的 Activity。该 Activity 与同一应用中的其他 Activity 具有相同的亲和性(默认应用亲和性),并通过此属性支持重新归属。当您的某个 Activity 启动该天气预报 Activity 时,该天气预报 Activity 最初会和您的 Activity 同属于一个任务。不过,当旅行应用的任务进入前台运行时,该天气预报 Activity 就会被重新分配给该任务并显示在其中。
举例说明
描述
MainActivity 跳转到AAAActivity,然后跳转到BBBActivity,再跳转到CCCActivity,最后跳转到DDDActivity。然后由DDDActivity跳转到BBBActivity。
<1> 所有Activity的启动模式都是默认模式。
完成所有跳转 查看Activity栈信息(Terminal 输入 adb shell dumpsys activity activities)
上一节降到Activity通过Intent或是Bundle传递数据(对象)需要序列化。那么什么是对象序列化,为什么要对象序列化,怎么对象序列化呢。
1.什么是序列化
简单来说,对象序列化,就是把运行时的对象信息,按照一定的规则,翻译成一串有迹可循的二进制流,然后将此二进制流,从一方传输到另一方。而在接收方,在接受到此二进制流之后,可以按照约定好的解析规则,进行反序列化,将对象信息解析出来,得到有用的数据信息。
再说的白一点就是将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
对象信息,包括Class信息、继承关系、访问权限、变量类型以及数值信息等。因此,序列化后得到的二进制流,不仅仅包含了描述一个对象的Class的关键信息,也存储了具有实际意义的数值信息。因此,序列化可以描述为——转述对象信息,存储对象数据。
2.为什么要序列化
Android开发的时候,无法将对象的引用传给Activitie或者Fragment,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。所以要序列化。
3.怎么序列化
Android中Intent如果要传递类对象,可以通过两种方式实现。
方式一:Serializable,要传递的类实现Serializable接口传递对象。Java自带
方式二:Parcelable,要传递的类实现Parcelable接口传递对象。android 专用
下面来一一讲解两种方式的实现
<1> Serializable
Java Bean
package com.wjn.lubandemo.bean;
import java.io.Serializable;
public class PictureBean implements Serializable {
private static final long serialVersionUID = 73823513598685L;
private String originArg;
private String thumbArg;
private String path;
private int image;
public String getOriginArg() {
return originArg;
}
public void setOriginArg(String originArg) {
this.originArg = originArg;
}
public String getThumbArg() {
return thumbArg;
}
public void setThumbArg(String thumbArg) {
this.thumbArg = thumbArg;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public int getImage() {
return image;
}
public void setImage(int image) {
this.image = image;
}
}
传递
PictureBean pictureBean=new PictureBean();
pictureBean.setImage(123);
pictureBean.setOriginArg("wjncpy0");
pictureBean.setPath("path");
pictureBean.setThumbArg("cpywjn1");
Intent intent=new Intent(MainActivity.this,EventActivity.class);
intent.putExtra("bean",pictureBean);
startActivity(intent);
接收
Intent intent = getIntent();
PictureBean pictureBean = (PictureBean) intent.getSerializableExtra("bean");
if (null != pictureBean) {
String s = pictureBean.getOriginArg();
String s1 = pictureBean.getPath();
String s2 = pictureBean.getThumbArg();
int s3 = pictureBean.getImage();
Log.d("TAG", "s----:" + s);
Log.d("TAG", "s1----:" + s1);
Log.d("TAG", "s2----:" + s2);
Log.d("TAG", "s3----:" + s3);
}
结果
D/TAG: s----:wjncpy0
D/TAG: s1----:path
D/TAG: s2----:cpywjn1
D/TAG: s3----:123
<2> Parcelable
Java Bean
package com.wjn.lubandemo.bean;
import android.os.Parcel;
import android.os.Parcelable;
public class Student implements Parcelable {
private int age;
private String name;
private long ids;
private double money;
public Student(Parcel in) {
age = in.readInt();
name = in.readString();
ids = in.readLong();
money = in.readDouble();
}
public static final Creator CREATOR = new Creator() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(age);
dest.writeString(name);
dest.writeLong(ids);
dest.writeDouble(money);
}
public Student(){
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setIds(long ids) {
this.ids = ids;
}
public long getIds() {
return ids;
}
public void setMoney(double money) {
this.money = money;
}
public double getMoney() {
return money;
}
}
传递
Student student=new Student();
student.setAge(12);
student.setName("张三");
student.setIds(123456789);
student.setMoney(12.56);
Intent intent=new Intent(MainActivity.this,EventActivity.class);
intent.putExtra("bean",student);
startActivity(intent);
接收
Intent intent = getIntent();
Student student = intent.getParcelableExtra("bean");
if (null != student) {
int age = student.getAge();
String name = student.getName();
long ids = student.getIds();
double money = student.getMoney();
Log.d("TAG", "age----:" + age);
Log.d("TAG", "name----:" + name);
Log.d("TAG", "ids----:" + ids);
Log.d("TAG", "money----:" + money);
}
结果
D/TAG: age----:12
D/TAG: name----:张三
D/TAG: ids----:123456789
D/TAG: money----:12.56
Serializable 和Parcelable的对比
编码方面
Serializable代码量少,写起来方便。
Parcelable代码多一些。
效率上
Parcelable的速度比高十倍以上。Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
Activity,Window与View的关系
流程解析: Activity调用startActivity后最后会调用attach方法,然后在PolicyManager实现一个Ipolicy接口,接着实现一个Policy对象,接着调用makenewwindow(Context)方法,该方法会返回一个PhoneWindow对象,而PhoneWindow 是Window的子类,在这个PhoneWindow中有一个DecorView的内部类,是所有应用窗口的根View,即View的老大, 直接控制Activity是否显示(引用老司机原话..),好吧,接着里面有一个LinearLayout,里面又有两个FrameLayout他们分别拿来装ActionBar和CustomView,而我们setContentView()加载的布局就放到这个CustomView中!
总结下这三者的关系: 打个牵强的比喻: 我们可以把这三个类分别堪称:画家,画布,画笔画出的东西; 画家通过画笔( LayoutInflater.infalte)画出图案,再绘制在画布(addView)上! 最后显示出来(setContentView)