第一章 四大组件 之 Activity(一)

文章目录

  • 第一组件 Activity
    • (一)Activity生命周期
      • 1、生命周期五大状态
      • 2、生命周期流程
      • 3、常见场景的生命周期调用方式
      • 4、具体场景生命周期调用方式
        • (1)横竖屏切换对Activiy生命周期影响
        • (2)启动Activity A
        • (3)按back返/在Activity A调用finish()方法
        • (4)按home/打开进入另一个Activity B
        • (5)再次进入Activity A
        • (6)dialog对话框
          • (6.1)Android组件Dialog
          • (6.2)Theme为Dialog的Activity
    • (二)Activity之间传递数据(6种方式)
      • (1)通过Intent传递数据(简单数据类型或可序列化对象)
        • 1.1)传统Intent
          • 1.1.1)传递基本数据类型
          • 1.1.2)传递多种数据类型(Bundle)
          • 1.1.3)传递对象
            • Serializable
            • Parcelable
        • 1.2)startActivityForResult + setResult方式
      • (2)通过静态变量传递数据(不建议)
      • (3)通过全局对象传递数据(Application)
      • (4)EventBus
      • (5)借助外部存储
      • (6)LocalBroadcast
    • (三)从Activity返回数据
    • (四)Activity启动过程
      • 1、整体流程
        • (1)Launcher通知AMS启动该APP的MainActivity,也就是清单文件设置启动的Activity
        • (2)AMS记录要启动的Activity信息,并且通知Launcher进入pause状态。Launcher进入pause状态后,通知AMS已经paused了,可以启动app了。
        • (3)app未开启过,所以AMS启动新的进程,并且在新进程中创建ActivityThread对象,执行其中的main函数方法。app主线程启动完毕后通知AMS,并传入applicationThread以便通讯。
        • (4)AMS通知app绑定Application。
        • (5)app启动MainActivitiy,并且创建和关联Context,最后调用onCreate方法。
      • 2、总结
    • (五)Activity四种启动模式
      • (1)标准Standard
      • (2)栈顶复用SingleTop
      • (3)栈内复用SingleTask
      • (4)单例SingleInstance
      • (5)启动模式总结
      • (6)任务栈
        • (6.1)什么是任务栈
        • (6.2)taskAffinity
        • (6.2)allowTaskReparenting属性
      • (7)Android退出整个应用解决方案
        • 1、利用SingTask
        • 2、利用历史栈和SingleTop
        • 3、通过广播来完成退出功能
        • 4、使用退出类
    • (六)Activity现场保存状态
      • (1)场景
      • (2)原理
      • (3)生命周期
      • (4)源码
        • 4.1)保存Activity状态
        • 4.2)恢复Activity状态
          • 4.2.1)在onCreate()方法中恢复Activity状态
          • 4.2.2)在onRestoreInstanceState()方法中恢复Activity状态
      • (5)补充
        • 5.1)如何避免配置改变时Activity重启?

第一组件 Activity

Activity是Android组件中最基本也是最为常见用的四大组件(Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器)之一 。
Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务。
Activity中所有操作都与用户密切相关,是一个负责与用户交互的组件,可以通过setContentView(View)来显示指定控件。
在一个android应用中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。Activity之间通过Intent进行通信。

(一)Activity生命周期

1、生命周期五大状态

(1)启动状态:Activity的启动状态很短暂,当Activity启动后便会进入运行状态。
(2)运行状态:Activity在此状态时处于屏幕最前端,它是可见、有焦点的,可以与用户进行交互。如单击、长按等事件。即使出现内存不足的情况,Android也会先销毁栈底的Activity,来确保当前的Activity正常运行。
(3)暂停状态:在某些情况下,Activity对用户来说仍然可见,但它无法获取焦点,用户对它操作没有没有响应,此时它处于暂停状态。
(4)停止状态:当Activity完全不可见时,它处于停止状态,但仍然保留着当前的状态和成员信息。如系统内存不足,那么这种状态下的Activity很容易被销毁。
(5)销毁状态:当Activity处于销毁状态时,将被清理出内存。

2、生命周期流程

第一章 四大组件 之 Activity(一)_第1张图片
启动Activity方法的生命周期调度:

  • 比方说我们点击跳转一个新Activity,这个时候Activity会入栈,同时它的生命周期也会从onCreate()到onResume()开始变换,这个过程是在ActivityStack里完成的,ActivityStack
    是运行在Server进程里的,这个时候Server进程就通过ApplicationThread的代理对象ApplicationThreadProxy向运行在app进程ApplicationThread发起操作请求。
  • ApplicationThread接收到操作请求后,因为它是运行在app进程里的其他线程里,所以ApplicationThread需要通过Handler向主线程ActivityThread发送操作消息。
  • 主线程接收到ApplicationThread发出的消息后,调用主线程ActivityThread执行响应的操作,并回调Activity相应的周期方法。

3、常见场景的生命周期调用方式

第一章 四大组件 之 Activity(一)_第2张图片

4、具体场景生命周期调用方式

(1)横竖屏切换对Activiy生命周期影响

横竖屏切换涉及到的是Activity的android:configChanges属性:
android:configChanges可以设置的属性值有:
orientation:消除横竖屏的影响
keyboardHidden:消除键盘的影响
screenSize:消除屏幕大小的影响
【情况1】
1、android:configChanges=orientation
2、android:configChanges=orientation|keyboardHidden
3、不设置android:configChanges
横竖屏切换Activity生命周期变化:
onPause–>onSaveInstanceState–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume
在进行横竖屏切换的时候在调用onStop之前会调用onSaveInstanceState来进行Activity的状态保存,随后在重新显示该Activity的onResume方法之前会调用onRestoreInstanceState来恢复之前由onSaveInstanceState保存的Activity信息
【情况2】
1、android:configChanges=orientation|screenSize
2、android:configChanges=orientation|screenSize|keyboardHidden
横竖屏切换不会重新加载Activity的各个生命周期
【情况3】
屏蔽横竖屏切换操作,不会出现切换的过程中Activity生命周期重新加载的情况
方法1:清单文件
android:screenOrientation=“portrait” 始终以竖屏显示
android:screenOrientation=“landscape” 始终以横屏显示
方法2:动态Activity
Activity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);以竖屏显示
Activity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);以横屏显示

(2)启动Activity A

onCreate–>onStart -->onResume

(3)按back返/在Activity A调用finish()方法

onPause -->onStop–>onDestroy

(4)按home/打开进入另一个Activity B

onPause -->onStop

(5)再次进入Activity A

onReStart–>onStart -->onResume

(6)dialog对话框

(6.1)Android组件Dialog

Activity仍位于前台,不影响Activity生命周期

(6.2)Theme为Dialog的Activity

Activity A启动对话框onPause
Activity A关闭对话框onResume

面试题:两个Activity之间跳转时必然会执行的是哪几个方法?
答:当在A Activity里面激活B Activity的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。
这个时候B覆盖了A的窗体, A会调用onStop()方法。
如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。
如果B已经存在于Activity栈中,B就不会调用onCreate()方法。
故一定会执行A的onPause()和B的onStart()与onResume()。

(二)Activity之间传递数据(6种方式)

(1)通过Intent传递数据(简单数据类型或可序列化对象)

1.1)传统Intent

1.1.1)传递基本数据类型

发送数据

   Intent intent =new Intent(EX06.this,OtherActivity.class); 
   intent.putExtra("boolean_key", true);
   intent.putExtra("string_key", "string_value");
   startActivity(intent);

获取数据

   Intent intent=getIntent();
   intent.getBooleanExtra("boolean_key",false);
   intent.getStringExtra("string_key");
1.1.2)传递多种数据类型(Bundle)

发送数据

	Intent intent =new Intent(CurrentActivity.this,OtherActivity.class);
	Bundle bundle =new Bundle();
	bundle.putBoolean("boolean_key", true);
	bundle.putString("string_key", "string_value");
	intent.putExtra("key", bundle);// 封装对象
	startActivity(intent);// 启动新的 Activity

获取数据

Intent intent =getIntent();
Bundle bundle =intent.getBundleExtra("key");
bundle.getBoolean("boolean_key");
bundle.getString("string_key");
1.1.3)传递对象
Serializable

对象序列化

public class Person implements Serializable {

    private String name;
    private int age;

    public Person() {}

    public void setName(String name){
        this.name = name;
    }

    public void setAge(int age){
        this.age = age;
    }

    public String getName(){
        return name;
    }

    public int getAge(){
        return age;
    }

}

发送数据

				Person person = new Person();
                person.setName("chenjy");
                person.setAge(18);

                Bundle bundle = new Bundle();
                bundle.putSerializable("person",person);

                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                intent.putExtras(bundle);
                startActivity(intent);

获取数据

Person person = (Person)getIntent().getSerializableExtra("person");

这种序列化是通过反射机制从而削弱了性能,这种机制也创建了大量的临时对象从而引起GC频繁回收调用资源。

Parcelable

Parcelable是由Android提供的序列化接口,google做了大量的优化
对象序列化

public class Person implements Parcelable {

    private String name;
    private int age;

    public Person() {}

    protected Person(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }

    public void setName(String name){
        this.name = name;
    }

    public void setAge(int age){
        this.age = age;
    }

    public String getName(){
        return name;
    }

    public int getAge(){
        return age;
    }


    public static final Creator CREATOR = new Creator() {
        @Override
        public Person createFromParcel(Parcel in) {
            Person person = new Person();
            person.name = in.readString();
            person.age = in.readInt();
            return person;
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
     dest.writeString(name);
     dest.writeInt(age);
    }
}

1.2)startActivityForResult + setResult方式

startActivityForResult

public class Activity1 extends Activity
{
    private TextView tetxtview;
    private Button btn;
    private final int REQUESTCODE=1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1);
        tetxtview=(TextView) findViewById(R.id.tetxtview);
        btn=(Button) findViewById(R.id.btn);
        btn.setText("跳转到Activity2");
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Activity1.this, Activity2.class);
                intent.putExtra("data", "123");
                startActivityForResult(intent, REQUESTCODE);
            }
        });
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if(resultCode==RESULT_OK)
        {
            if(requestCode==REQUESTCODE)
            {
                tetxtview.setText("收到信息:【"+intent.getStringExtra("data")+"】");
            }
        }
    }
 
}

setResult

public class Activity2 extends Activity
{
    private TextView tetxtview;
    private Button btn;
    private String data;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1);
        data=getIntent().getStringExtra("data");
        tetxtview=(TextView) findViewById(R.id.tetxtview);
        tetxtview.setText("收到信息:【"+data+"】");
        btn=(Button) findViewById(R.id.btn);
        btn.setText("回到到Activity1");
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=getIntent();
                intent.putExtra("data","456");
                setResult(RESULT_OK, intent);
                finish();
            }
        });
    }
}

(2)通过静态变量传递数据(不建议)

设置静态变量

public class OtherActivity extends Activity {
    public static String name;
    public static String age;
    public static String address;  

直接访问静态变量

Intent intent = new Intent(MainActivity.this,OtherActivity.class);
//直接访问OtherActivity的三个静态变量的值  
OtherActivity.name = "wulianghuan";
OtherActivity.age = "22";
OtherActivity.address = "上海闵行";
startActivity(intent); 

(3)通过全局对象传递数据(Application)

如果想使某些数据长时间驻留内存,以便程序随时调用,建议采用全局对象。Application全局类不需要定义静态变量只要定义普通成员变量即可,但全局类中必须有一个无参构造方法,编写完Application类后,还需要在标签中制定全局类名,否则系统不会自动创建全局对象。
MainApplication

public class MainApplication extends Application {
    private String username; //Application设置应用的全局变量
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
}

清单文件


设置&获取全局对象

public class MainActivity extends Activity {
    application =(MainApplication)getApplication();
       application.setUsername("sunzn");
}
public class OtherActivity extends Activity {
    application = (MainApplication) getApplication();
    username = application.getUsername();
}

(4)EventBus

但是当传输的数据量较大的时候Parcelable虽然很便捷,但是会出现异常TransactionTooLargeException。只时候就需要用到插件EventBus。
EventBus 使用的是发布 订阅者模型,发布者通过EventBus发布事件,订阅者通过EventBus订阅事件。当发布者发布事件时,订阅该事件的订阅者的事件处理方法将被调用。
定义事件

public class MessageEvent {

    private String message;

    public MessageEvent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

订阅事件
使用@Subscribe注解来定义订阅者方法,方法名可以是任意合法的方法名,参数类型为订阅事件的类型

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
    ...
}

@Subscribe(threadMode = ThreadMode.MAIN)中使用了ThreadMode.MAIN这个模式,表示该函数在主线程即UI线程中执行
EventBus总共有四种线程模式,分别是:

ThreadMode.MAIN:表示无论事件是在哪个线程发布出来的,该事件订阅方法onEvent都会在UI线程中执行,这个在Android中是非常有用的,因为在Android中只能在UI线程中更新UI,所有在此模式下的方法是不能执行耗时操作的。
ThreadMode.POSTING:表示事件在哪个线程中发布出来的,事件订阅函数onEvent就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
ThreadMode.BACKGROUND:表示如果事件在UI线程中发布出来的,那么订阅函数onEvent就会在子线程中运行,如果事件本来就是在子线程中发布出来的,那么订阅函数直接在该子线程中执行。
ThreadMode.AYSNC:使用这个模式的订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程来执行订阅函数。

订阅者还需要在总线上注册,并在不需要时在总线上注销

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // 注册订阅者
    EventBus.getDefault().register(this);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 注销订阅者
    EventBus.getDefault().unregister(this);
}    

发布事件

EventBus.getDefault().post(new MessageEvent("Post Event!"));

(5)借助外部存储

包括SharedPreference 、Android数据库SQLite 、File

(6)LocalBroadcast

在同一个应用程序内,进行通信的组件。它通过 LocalBroadcastManager (以下简称 LBM),来实现注册、解注、发送广播等操作。
它和原有的 BroadcastReceiver (Global)相比而言,好处有:
1、因 LocalBroadcast 只在本应用内,所以完全无需担心隐私数据被泄露的问题。
2、LocalBroadcast 的发送和接收更可控。
3、比原有的 BroadcastReceiver 更高效。

(三)从Activity返回数据

要从Activity返回数据,需要使用startActivityForResult方法来显示Activity。
1、 从Activity1跳转到Activity2:startActivityForResult(intent,requestCode)

Intent intent = new Intent();
 intent = intent.setClass(ActivityIntent.this, AnotherActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("string", et_string.getText().toString());
        intent.putExtras(bundle);
        startActivityForResult(intent,0);

2、 从Activity2返回数据到Activity1:setResult(resultCode,Intent data)

Intent intent = new Intent();
intent = intent.setClass(AnotherActivity.this, ActivityIntent.class);
Bundle bundle = new Bundle();
bundle.putInt("result", "Activity2的处理结果");
intent.putExtras(bundle);
AnotherActivity.this.setResult(RESULT_OK, intent); //RESULT_OK是返回状态码
AnotherActivity.this.finish();

3、 在Activity1中重写onActivityResault方法,接受数据:重写onActivityResult(requestCode,resultCode)

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch(resultCode) { //根据状态码,处理返回结果
        case RESULT_OK:
        Bundle bundle =data.getExtras(); //获取intent里面的bundle对象
        String result = bundle.getInt("result");
        break;
default:
        break;
        }

(四)Activity启动过程

Activity启动过程,是Activity与ActivityManagerService以Binder为通讯方式进行多次通讯的结果。

1、整体流程

(1)Launcher通知AMS启动该APP的MainActivity,也就是清单文件设置启动的Activity

手机桌面也是一个app,每一个应用的icon都罗列在Launcher上,点击icon触发onItemClick事件,下面例如我们要启动某个app,首先我们要在清单文件定义默认启动的Activity信息。


            
                

                
            

然后Launcher获取该信息后,启动App

//该应用的包名
            String pkg = info.activityInfo.packageName;
            //应用的主activity类
            String cls = info.activityInfo.name;

            ComponentName componet = new ComponentName(pkg, cls);

            Intent i = new Intent();
            i.setComponent(componet);
            startActivity(i);

启动Activity由ActivityManagerService(AMS)全权管理,他们之间的通讯需要使用Binder,Activity通过Binder与AMS多次通讯,才能启动app。
startActivityForResult
我们从Activity的startActivity方法开始分析。
startActivity方法有好几种重载方式,但它们最终都会调用startActivityForResult方法。

 @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

在startActivityForResult方法内,会调用Instrumentation的execStartActivity方法

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {

            ......

            Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            ......
}

Instrumentation
Instrumentation从字面上来看是仪器盘的意思,具体到程序中是管理activity的一个工具类,包括创建和启动Activity,activity的生命周期方法都是由Instrumentation这个仪器来控制,一个进程中只用一个Instrumentation实例。

  /**
     *
     *
     * @param who The Context from which the activity is being started.activity所在上下文
     * @param contextThread The main thread of the Context from which the activity
     *                      is being started.上下文所在主线程
     * @param token Internal token identifying to the system who is starting 
     *              the activity; may be null.启动的activity标识
     * @param target Which activity is performing the start (and thus receiving 
     *               any result);
     *               may be null if this call is no`t being made form an activity.
     * @param intent The actual Intent to start.传入的Intent
     * @param requestCode Identifier for this request's result; less than zero 
     *                    if the caller is not expecting a result.请求码
     * @param options Addition options.额外参数
     *
     */
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;

        ......

        try {
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

            //检查启动Activity的结果(抛出异常,例如清单文件未注册Activity)
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

下面我们来分析一下比较重要的2个参数,contextThread和token。
IBinder contextThread=mMainThread.getApplicationThread
ActivityThread通过内部类ApplicationThread用于进程间通讯的Binder对象

1、mMainThread实际上是ActivityThread对象。ActivityThread,就是主线程,也就是UI线程,它是在App启动时创建的,它代表了App应用程序。
2、通过构造方法我们就很清晰的可以得知原来这个ApplicationThreadNative就是相当于AIDL通讯中的Stub,也就是服务端,ApplicationThreadProxy即AIDL通讯中的Proxy,也就是客户端。详解见深入浅出AIDL二。所以ApplicationThread是通讯的具体实现类。

public abstract class ApplicationThreadNative extends Binder implements IApplicationThread {

    static public IApplicationThread asInterface(IBinder obj) {...}

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {...}

    public IBinder asBinder(){return this;}

}

class ApplicationThreadProxy implements IApplicationThread {
    private final IBinder mRemote;

    public ApplicationThreadProxy(IBinder remote) {
        mRemote = remote;
    }

    ...
}

IBinder token
token对象,是在Activity的attach方法中传入的,也就是Activity的创建与关联时候传入的Activity信息。 这也是个Binder对象,它代表了Launcher这个Activity,这里也通过Instrumentation传给AMS,AMS查询后,就知道是谁向AMS发起请求了。

contextThread和token这两个参数用于通讯,contextThread表示Activity上下文所在主线程,token为启动的Activity标识。传递给AMS,以后AMS想反过来通知该Activity,就能通过这两个参数,找到Activity。

IActivityManager
在Instrumentation中,启动Activity真正的实现是由ActivityManagerNative.getDefault()的startActivity方法来完成。

ActivityManagerService(下面简称AMS)继承自ActivityManagerNative(下面简称AMN),而AMN继承自Binder并实现了IActivityManager这个Binder接口,因此AMS也是一个Binder,它是IActivityManager的具体实现.

public final class ActivityManagerService extends ActivityManagerNative {...}
public abstract class ActivityManagerNative extends Binder implements IActivityManager{...}
public interface IActivityManager extends IInterface {...}

分析AIDL

  /**
     * Retrieve the system's default/global activity manager.
     */
    static public IActivityManager getDefault() {
        return gDefault.get();
    }

    private static final Singleton gDefault = new Singleton() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            IActivityManager am = asInterface(b);
            return am;
        }
    };

    /**
     * Cast a Binder object into an activity manager interface, generating
     * a proxy if needed.
     */
    static public IActivityManager asInterface(IBinder obj) {
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;//同一进程,返回Stub本地对象。
        }

        return new ActivityManagerProxy(obj);//跨进程,返回代理对象。
    }

可以发现,在AMN 中,AMS这个Binder对象采用单例模式对外提供,Singleton是一个单例的封装类,第一次调用它的get方法时它会通过create方法来初始化AMS这个Binder对象,在后续的调用中则直接返回之前创建的对象(使用同一个AMS)。

分析create方法,根据Binder分析,可以得知在IActivityManager内(相当于Client),通过应用程序中的0号引用,可以向SMgr获取服务端(Server)的Binder引用。
AMN通过getDefault方法,从ServiceManager中获取AMS中Binder的引用对象,然后将它转换成ActivityManagerProxy对象(简称AMP),AMP就是AMS的代理对象。类似AIDL中客户端的绑定代码,此时我们就可以通过ActivityManagerProxy(asInterface返回值为 IActivityManager),与AMS进行通讯。
第一章 四大组件 之 Activity(一)_第3张图片
从上面的分析可以知道,Activity是由AMN.getDefault()来启动的,而AMN.getDefault()实际上是AMS,因此Activity的启动过程又转移到了AMS中,为了继续分析这个过程,只需要查看AMS的startActivity方法即可。
第一章 四大组件 之 Activity(一)_第4张图片

(2)AMS记录要启动的Activity信息,并且通知Launcher进入pause状态。Launcher进入pause状态后,通知AMS已经paused了,可以启动app了。

ActivityManagerService
AMS的startActivity方法实际调用mActivityStarter的startActivityMayWait方法

//AMS

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {

        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }


    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);

        //7.0Acitivty启动管理类新增ActivityStarter(原本是ActivityStackSupervisor处理该过程)
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null);
    }

ActivityStarter

//ActivityStarter

    final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {

            ``````

            //根据intent在系统中找到合适的应用的activity,如果有多个activity可选择,
            //则会弹出ResolverActivity让用户选择合适的应用。
            ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
                profileFile, profileFd, userId);

            ``````

            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask);

            ``````

            return res;
    }



    //在startActivityLocked方法里,对传过来的参数做一些校验,然后创建ActivityRecord对象,再调用startActivityUnchecked(7.0前是startActivityUncheckedLocked)方法启动Activity。
    final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;

        ``````
        //创建ActivityRecord对象
        //ActivityRecord  :  在AMS中,将用ActivityRecord来作为Activity的记录者,每次启动一个Actvity会有一个对应的ActivityRecord对象,表示Activity的一个记录
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
                options, sourceRecord);

        ``````

        err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                true, options, inTask);


        //此处将通知ActivityStarter, Activity对应的Task被移动到前台
        postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);

        return err;
    }
//ActivityStarter

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {

            ``````
        //ActivityStack的startActivityLocked,不要搞混了。同时调用WindowManager准备App切换相关的工作
        //将ActivityRecord(当前Activity)加入回退栈
        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);


        if (mDoResume) {

            final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                // If the activity is not focusable, we can't resume it, but still would like to
                // make sure it becomes visible as it starts (this will also trigger entry
                // animation). An example of this are PIP activities.
                // Also, we don't want to resume activities in a task that currently has an overlay
                // as the starting activity just needs to be in the visible paused state until the
                // over is removed.

            } else {
                //最终调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }

}

(1)在startActivityLocked方法里,对传过来的参数做一些校验(检查调用者权限)
(2)然后创建ActivityRecord对象,ActivityRecord代表要开启的Activity信息,内封装了很多信息。再调用startActivityUnchecked方法启动Activity。
(3)startActivityUnchecked方法负责调度ActivityRecord和Task。理解该方法是理解Actvity启动模式(默认standard:每启动一次Activity,就会创建一个新的Activity的实例并将该实例置于栈顶)的关键。startActivityUnchecked方法调度task的算法非常复杂,和当前回退栈,要启动的acitivity的启动模式以及taskAffinity属性,启动activity时设置的intent的flag等诸多要素相关。
1、调用ActivityStack的startActivityLocked将ActivityRecord加入回退栈,如果这是首次打开的应用,则会被放入ActivityTask栈顶
2、最终调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked
ActivityStackSupervisor

//ActivityStackSupervisor

    boolean resumeFocusedStackTopActivityLocked() {
        return resumeFocusedStackTopActivityLocked(null, null, null);
    }

    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
        //待启动Activity对应的Task为前台Task时,调用该Task对应ActivityStack的resumeTopActivityUncheckedLocked函数
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || r.state != RESUMED) {
        //否则只是调用当前前台栈的resumeTopActivityUncheckedLocked
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        }
        return false;
    }

ActivityStack

//ActivityStack


    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {

        ``````
        result = resumeTopActivityInnerLocked(prev, options);

        return result;
    }


    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {


        //mResumedActivity指向上一次启动的Activity(Launcher)
        if (mResumedActivity != null) {
            ``````

           //通知Launcher进入pause状态
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }
         if (pausing) {//Launcher已经暂停了
            ``````

            if (next.app != null && next.app.thread != null) {
                //如果app已经启动过
                //调用淘宝(待启动)Activity所在进程的优先级,保证其不被kill
                mService.updateLruProcessLocked(next.app, true, null);
            }

        } 
        ``````

        if (next.app != null && next.app.thread != null) {

        //如果Intent不为空,调用NewIntent方法传入Intent
        next.app.thread.scheduleNewIntent(next.newIntents, next.appToken, false);

        //假设淘宝App已经启动,点击Home键返回到Launcher,再次从Launcher启动淘宝(或者第三方启动已开启的App)
        next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                        mService.isNextTransitionForward(), resumeAnimOptions);
        ``````

        } else {
        ``````
           //创建进程,冷启动Activity。或者已启动App,重新启动Activity
           mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

        return true;
    }

resumeTopActivityInnerLocked主要执行2个功能:
1、找出还没结束的首个ActivityRecord,如果一个没结束的Activity都没有,就开启Launcher程序,否则先需要暂停当前的Activity。因为我们是在Lancher中启动mainActivity,所以当前mResumedActivity!=null,调用startPausingLocked()使得Launcher进入暂停状态
2、判断是否需要重新启动目标Activity,即Activity是否已经启动过。(例如保存在后台,应用切换)

(3)app未开启过,所以AMS启动新的进程,并且在新进程中创建ActivityThread对象,执行其中的main函数方法。app主线程启动完毕后通知AMS,并传入applicationThread以便通讯。

ActivityStackSupervisor

    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {

                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                //目标Activity的App已经启动(存在ActivityThread),则重启Activity
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
               ``````
            }
        }

        //如果进程不存在,则通过zygote创建应用进程。
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

ActivityStackSupervisor的startSpecificActivityLocked用于创建新的进程并启动Activity,分为2种情况:
(1)如App未启动,例如从Launcher冷启动App,则需要创建新进程,通过AMS调用Zygote(受精卵)孵化应用进程。
(2)如果App已经启动,例如从MainActivity跳转到LoginActivity,则通过realStartActivityLocked启动。
ActivityManagerService
我们以Launcher启动App(App未开启过),故通过AMS创建新的ActivityThread对象并进行Activity的绑定

//ActivityServiceManager

        //Process.java的start函数,将通过socket发送消息给zygote
        //zygote将派生出一个子进程,子进程将通过反射调用ActivityThread的main函数
        Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);

Zygote进程孵化出新的应用进程后,通过反射执行ActivityThread类的main方法。在该方法里会先准备好Looper和消息队列,然后调用attach方法将应用进程绑定到AMS,然后进入loop循环,不断地读取消息队列里的消息,并分发消息。
ActivityThread

//ActivityThread

public static void main(String[] args) {
    ``````
    //准备主线程的Looper,下篇博文分析Handler,Looper
    Looper.prepareMainLooper();

    //创建当前进程的ActivityThread
    ActivityThread thread = new ActivityThread();

    //将该进程绑定到AMS
    thread.attach(false);

    if (sMainThreadHandler == null) {
    //保存进程对应的主线程Handler
        sMainThreadHandler = thread.getHandler();
    }

    ``````
    //进入主线程的消息循环
    Looper.loop();

    ``````
}

//上面说过,ApplicationThread是ActivityThread用来与AMS通讯的中介
final ApplicationThread mAppThread = new ApplicationThread();

private void attach(boolean system) {
    if (!system) {
        final IActivityManager mgr = ActivityManagerNative.getDefault();

        //调用AMS的attachApplication方法,将ApplicationThread对象绑定至ActivityManagerService
        //这样AMS就可以通过ApplicationThread代理对象控制应用进程

            mgr.attachApplication(mAppThread);
    } else {
        ``````
    }
}

至此,进程创建完毕,拥有了主线程,并通过attach方法绑定到AMS

AMS启动Activity大致流程
第一章 四大组件 之 Activity(一)_第5张图片

(4)AMS通知app绑定Application。

此时,有了app进程和主线程,但仍是一幅空壳。没有activity信息,也没有关联上下文。
AMS通过传入的applicationThread通知ActivityThread绑定Application并启动Activity。
AMS

   @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            //通过Binder获取proxy(ApplicationThread)方的进程id(也就是淘宝应用进程id)
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {

        // Find the application record that is being attached...  either via
        // the pid if we are running in multiple processes, or just pull the
        // next app record if we are emulating process with anonymous threads.
        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid);
            }
        } else {
            app = null;
        }

        //因为进程由AMS启动,所以在AMS中一定会有ProcessRecord(进程记录)
        //如果没有ProcessRecord,则需要杀死该进程并退出
        if (app == null) {
            ``````
            return false;
        }

        // If this application record is still attached to a previous
        // process, clean it up now.
        if (app.thread != null) {
            //如果从ProcessRecord中获取的IApplicationThread不为空,则需要处理该IApplicationThread
            //因为有可能此Pid为复用,旧应用进程刚释放,内部IApplicationThread尚未清空,
            //同时新进程又刚好使用了此Pid
            handleAppDiedLocked(app, true, true);
        }


        //创建死亡代理(进程kill后通知AMS)
        AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);

        //进程注册成功,移除超时通知
        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        ``````
        try {
            //******绑定Application******
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());

            updateLruProcessLocked(app, false, null);
        } catch (Exception e) {

            ``````
            //bindApplication失败后,重启进程
            startProcessLocked(app, "bind fail", processName);
            return false;
        }

        try {
            //******启动Activity(启动淘宝MainActivity)******
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;//didSomething表示是否有启动四大组件
            }
        } catch (Exception e) {
            badApp = true;
        }

        ``````
        //绑定service和Broadcast的Application


        if (badApp) {
            //如果以上组件启动出错,则需要杀死进程并移除记录
            app.kill("error during init", true);
            handleAppDiedLocked(app, false, true);
            return false;
        }

        //如果以上没有启动任何组件,那么didSomething为false
        if (!didSomething) {
            //调整进程的oom_adj值, oom_adj相当于一种优先级
            //如果应用进程没有运行任何组件,那么当内存出现不足时,该进程是最先被系统“杀死”
            updateOomAdjLocked();
        }
        return true;
    }

在在attachApplicationLocked中有两个比较重要的方法函数:
1、thread.bindApplication(…) : 绑定Application到ActivityThread
2、mStackSupervisor.attachApplicationLocked(app) : 启动Activity(7.0前为mMainStack.realStartActivityLocked())
ApplicationThread
ActivityThread通过ApplicationThread与AMS进行通讯,所以上面的thread.bindApplication(…)方法,就应该是通过ApplicationThread进行传达。即,AMS通过ApplicationThread通知ActivityThread进行绑定Application

private class ApplicationThread extends ApplicationThreadNative {

        public final void bindApplication(...一大堆参数...) {
            AppBindData data = new AppBindData();
            //给data设置参数...
            ``````

            sendMessage(H.BIND_APPLICATION, data);
        }
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        Message msg = Message.obtain();
        //给msg设置参数
        ``````
        mH.sendMessage(msg);
    }

H
发送消息是通过H的Handler类来完成的

private class H extends Handler {
        public static final int LAUNCH_ACTIVITY         = 100;
        public static final int PAUSE_ACTIVITY          = 101;
        ``````
        public static final int RESUME_ACTIVITY         = 107;

        public static final int DESTROY_ACTIVITY        = 109;
        public static final int BIND_APPLICATION        = 110;
        public static final int EXIT_APPLICATION        = 111;

        ``````

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;

                ``````
                //绑定application
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

            }

        }

    }

可以看出,这个H类相当于ActivityThread和ApplicationThread的中介人,也就是拉皮条的。ActivityThread通过ApplicationThread与AMS通讯。 ApplicationThread通过H与ActivityThread通讯,处理Activity事务。
上面ApplicationThread给H发送BIND_APPLICATION标识,在H中,通过handleBindApplication处理application的绑定事务。
ActivityThread

 private void handleBindApplication(AppBindData data) {

           ``````
          //根据传递过来的ApplicationInfo创建一个对应的LoadedApk对象
          data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);//获取LoadedApk


          /**
          * For apps targetting Honeycomb or later, we don't allow network usage
          * on the main event loop / UI thread. This is what ultimately throws
          * {@link NetworkOnMainThreadException}.
          */
          //禁止在主线程使用网络操作
          if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
              StrictMode.enableDeathOnNetwork();
          }
          /**
           * For apps targetting N or later, we don't allow file:// Uri exposure.
           * This is what ultimately throws {@link FileUriExposedException}.
           */
           //7.0引入Fileprovide
          if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
              StrictMode.enableDeathOnFileUriExposure();
          }

          ``````
          //创建进程对应的Android运行环境ContextImpl
          final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);


          if ((InstrumentationInfo)ii != null) {
               ``````
          } else {
               //注意Activity的所有生命周期方法都会被Instrumentation对象所监控,
               //也就说执行Activity的生命周期方法前后一定会调用Instrumentation对象的相关方法
               mInstrumentation = new Instrumentation();
          }

          try {
             ``````
             Application app = data.info.makeApplication(data.restrictedBackupMode, null);
             mInitialApplication = app;


             //加载进程对应Package中携带的ContentProvider
             installContentProviders(app, data.providers);

             ``````
             mInstrumentation.onCreate(data.instrumentationArgs);

             try {
                  //这里会调用Application的onCreate方法
                  //故此Applcation对象的onCreate方法会比ActivityThread的main方法后调用
                  //但是会比这个应用的所有activity先调用
                  mInstrumentation.callApplicationOnCreate(app);
              } catch (Exception e) {
                  ``````
              }
            } finally {
                StrictMode.setThreadPolicy(savedPolicy);
            }
        }

handleBindApplication的目的是让一个Java进程融入到Android体系中。
因此,该函数中的代码主要进行以下工作:
(1)按照Android的要求,完成对进程基本参数的设置置,包括设置进程名、时区、资源及兼容性配置;
(2)同时也添加了一些限制,例如主线程不能访问网络等。
(3)创建进程对应的ContextImpl、LoadedApk、Application等对象,同时加载Application中的ContentProvider,并初始化Application(onCreate())。
(4)使用Instrumentation监控Activity的生命周期。(一个进程对应一个Instrumentation实例)
当完成上述工作后,新建的进程终于加入到了Android体系。

这里的消息传递机制包含4个类:H、ApplicationThread、ActivityThread与AMS:
1、Binder消息传递:ActivityThread通过ApplicationThread与AMS通讯。
2、Handler消息传递:ApplicationThread通过H与ActivityThread通讯,处理Activity事务。
3、ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS以进程通讯的方式来完成ActivityThread的请求后调用ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行,即切换到主线程中去执行,这个过程就是主线程的消息循环模型。
4、使用H文件是因为:

  • 便于集中管理,方便打印Log日志等,H文件是大管家
  • AMS通过ApplicationThread回调到我们的进程,ApplicationThread是一个Binder,回调逻辑是在Binder线程池完成的,所以需要Handler H切换UI线程
    5、注:ActivityThread并不是一个线程Thread,它是final类并且无继承或者实现其它类,它的作用就是在main方法内消息循环,处理主线程事务。

(5)app启动MainActivitiy,并且创建和关联Context,最后调用onCreate方法。

绑定application后,便可启动Activity
ActivityStackSupervisor

    boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        boolean didSomething = false;

        //ActivityStackSupervisor维护着终端中所有ActivityStack
        //此处通过轮询,找出前台栈顶端的待启动Activity
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFocusedStack(stack)) {
                    continue;
                }

                ActivityRecord hr = stack.topRunningActivityLocked();
                if (hr != null) {
                    //前台待启动的Activity与当前新建的进程一致时,启动这个Activity
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {

                            //realStartActivityLocked进行实际的启动工作
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {

                        }
                    }
                }
            }
        }

        return didSomething;
    }

最终通过realStartActivityLocked启动activity

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

AMS最后通过ApplicationThread通知ActivityThread启动Activity,启动套路如绑定Application
ApplicationThread

//内部类ApplicationThread
    private class ApplicationThread extends ApplicationThreadNative {
        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List pendingResults, List pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();
            //设置参数
            ``````

            //从LAUNCH_ACTIVITY这个标识我们就可以知道,它就是用来启动Activity
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }
    }

H

  private class H extends Handler {
        ``````

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    //利用ApplicationInfo等信息得到对应的LoadedApk,保存到ActivityClientRecord
                    //ActivityClientRecord包含Activity相关的信息
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;

                ``````
            }
        }
    }

ActivityThread

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ``````

    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        ``````
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        ``````
    } 
    ``````
}

handleLaunchActivity方法里有有两个重要的函数调用,
(1)performLaunchActivity : 会调用Activity的onCreate,onStart,onResotreInstanceState方法。最终完成了Activity对象的创建和启动过程。
(2)handleResumeActivity : 会调用Activity的onResume方法.
performLaunchActivity
performLaunchActivity主要完成了如下几件事
(1)从ActivityClientRecord中获取待启动的Activity的组件信息。

ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }

        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

(2)通过Instrumentation的newActivity方法使用类加载器创建Activity对象。

 Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            ``````
        }

(3)通过LoadedApk的makeApplication方法来创建Application对象。

Application app = r.packageInfo.makeApplication(false, mInstrumentation);//r.packageInfo为LoadedApk对象

其实在我们上面的bindApplication中,我们就有介绍到通过LoadedApk创建Application,并且创建完毕后,通过Instrumentation的callApplicationOnCreate来调用Application的onCreate方法

Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    ``````
 mInstrumentation.callApplicationOnCreate(app);

所以第三步是为了判断Application是否为空,而且我们从makeApplication方法中也能看出如果Application已经被创建过了,那么就不会再重复创建了。
(4)创建ContextImpl对象,并通过Activity的attach方法来完成一些重要数据的初始化。

              Context appContext = createBaseContextForActivity(r, activity);//创建ContextImpl对象

                ``````
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);

ContextImpl是一个很重要的数据结构,它是Context的具体实现,Context中的大部分逻辑都是由ContextImpl来完成的。ContextImpl来完成的。ContextImpl是通过Activity的attach方法来和Activity建立关联的,除此之外,在attach方法中Activity还会完成Window的创建并建立自己和Window的关联,这样当Window接收到外部输入事件后就可以将事件传递给Activity。

(5)调用Activity的onCreate方法。

                mInstrumentation.callActivityOnCreate(activity, r.state);

由于Activity的onCreate已经被调用,这也意味着Activity已经完成了整个启动过程。
(6)调用Activity的onStart,onResotreInstanceState方法。

 		mInstrumentation.callActivityOnCreate(activity, r.state);
        ``````
        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);

2、总结

(1)流程图
第一章 四大组件 之 Activity(一)_第6张图片
(2)时序图
第一章 四大组件 之 Activity(一)_第7张图片
(3)总结
Activity的启动过程,我们可以从Context的startActivity说起,其实现是ContextImpl的startActivity
(1)首先会调用Activity的startActivityForResult,之后通过Instrumentation工具类获取一些用于通讯的参数(ContextThread、Token)并尝试启动Activity,这是一个跨进程过程,它会通过Binder机制调用AMS的startActivity方法
(2)当AMS校验完Activity的合法性后,会将当前Activity加入回退栈,并根据启动模式启动Activity
(3)因为是第一次启动Activity,应通过AMS调用Zygote创建新的应用进程,之后反射执行ActivityThread类的main方法,在该方法中准备好Looper和消息队列,并调用attach方法将applicationThread绑定到AMS用于通讯,然后进入Loop循环。
(4)AMS通过ApplicationThread通知ActivityThread绑定Application并启动Activity。AMS通过ApplicationThread回调到我们的进程,这也是一次跨进程过程,而applicationThread就是一个binder,回调逻辑是在binder线程池中完成的,所以需要通过Handler H将其切换到ui线程。
(5)绑定Application发送的消息是BIND_APPLICATION,对应的方法是handleBindApplication,该方法中对进程进行了配置,并创建及初始化了Application。
启动Activity发送的消息是LAUNCH_ACTIVITY,对应的方法handleLaunchActivity,在这个方法里完成了Activity的创建和启动,接着,在activity的onResume中,activity的内容将开始渲染到window上,然后开始绘制直到我们看见。

(五)Activity四种启动模式

决定是生成新的Activity还是重用已存在的Activity。Android 中默认启动模式为 standard,我们可以通过在 AndroidManifest.xml 的 activity 标签下通过 launchMode 属性指定我们想要设置的启动模式。

(1)标准Standard

1.1 特点
每启动一次Activity,就会创建一个新的Activity的实例并将该实例置于栈顶
(1)每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
(2)每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。

  • Activity默认启动模式
  • 因ApplicationContext没有任务栈,故无法采用标准模式启动Activity,但可通过为待启动的Activity(一般为MainActivity)指定标记位:FLAG_ACTIVITY_NEW_TASK,则启动时就会该Activity创建一个新的任务栈(实际上采用了singleTask模式)
    1.2 示意图
    第一章 四大组件 之 Activity(一)_第8张图片
    1.3 实例
    一个任务栈,每创建一个Activity就往栈顶增加一个实例
    创建ActivityA→Task1 Instance 1
    创建ActivityA→Task1 Instance2
    创建ActivityB→Task1 Instance3…
    1.4 场景
    正常的去打开一个新的页面,这种启动模式使用最多,最普通 。

(2)栈顶复用SingleTop

1.1 特点
启动Activity,若创建的Activity位于任务栈栈顶,则Activity的实例不会重建,而是重用栈顶的实例。(调用实例的onNewIntent(),可以通过intent传值,不调用onCreate()和onStart())
否则就创建该Activity新实例并置于栈顶

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

1.2 示意图
第一章 四大组件 之 Activity(一)_第9张图片
1.3 实例
打开步骤:MainActivity->SingleTaskActivity->SingleTaskActivity->OtherActivity->SingleTaskActivity->SingleTaskActivity
第一次启动SingleTopActivity的时候会执行onCreate()方法新建一个实例,然后再次启动SingleTopActivity页面会回调onNewIntent(),说明没有创建新的实例,而且hashCode值没有发生改变。此时我们继续打开另一个Activity,这时OtherActivity处于栈顶,我们继续启动SingleTopActivity,这时发现又是执行了onCreate(),说明又重新创建了新的实例,当我们继续启动SingleTopActivity,发现回调了onNewIntent(),同样hashCode值没有发生改变,证明没有重新创建实例。
1.4场景
singleTop适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面
假如一个新闻客户端,在通知栏收到了3条推送,点击每一条推送会打开新闻的详情页,如果为默认的启动模式的话,点击一次打开一个页面,会打开三个详情页,这肯定是不合理的。如果启动模式设置为singleTop,当点击第一条推送后,新闻详情页已经处于栈顶,当我们第二条和第三条推送的时候,只需要通过Intent传入相应的内容即可,并不会重新打开新的页面,这样就可以避免重复打开页面了。

(3)栈内复用SingleTask

1.1 特点
1.查看Activity所在的任务栈是否存在,若不存在则重建一个任务栈,创建Activity实例并置于栈顶(可通过TaskAffinity属性指定Activity想要的任务栈)
这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。不设置taskAffinity属性的话,默认为应用的包名。
2.若存在任务栈,则查看该Activity是否存在栈中,若不存在,则创建Activity实例并置于栈顶
3.若该Activity存在栈中,在将实例上的所有Activity出栈,使该Activity位于栈顶(回调onNewIntent())
1.2 示意图
第一章 四大组件 之 Activity(一)_第10张图片
1.3 实例
情况1:
SingleTaskActivity配置



打开步骤:MainActivity->SingleTaskActivity->SingleTaskActivity->OtherActivity->SingleTaskActivity->SingleTaskActivity
结果:首先,因为发现它们的taskId值都相同,所以它们同属于一个任务栈。其次,第一次启动SingleTaskActivity的时候会执行onCreate()方法新建一个实例,然后再次启动SingleTaskActivity页面会回调onNewIntent(),说明没有创建新的实例,而且hashCode值没有发生改变。此时我们继续打开另一个Activity,然后继续启动SingleTaskActivity,这时发现仍然只回调onNewIntent(),说明没有创建新的实例,当我们继续启动SingleTaskActivity,仍然只是回调了onNewIntent(),此过程中发现hashCode值始终没有发生改变,证明引用都是同一个的实例。
情况2:
设置taskAffinity属性,singleTask所在的Activity与启动它的Activity处于不同的任务栈中。
SingleTaskActivity配置



因为MainActivity没有指定taskAffinity属性,默认为包名,与SingleTaskActivity不同,所以在启动SingleTaskActivity时,发现这个栈不存在,系统首先会创建这个栈然后将SingleTaskActivity压入栈中。之后我们发现只要栈中存在SingleTaskActivity这个实例,就会直接引用。
1.4场景
SingleTask这种启动模式最常使用的就是一个APP的首页,因为一般为一个APP的第一个页面,且长时间保留在栈中,所以最适合设置singleTask启动模式来复用。

(4)单例SingleInstance

1.1 特点
单实例模式,顾名思义,只有一个实例。该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
创建一个Activity则新建一个任务栈,并将该Activity实例放入新栈。
一旦该模式的Activity实例已存在某个栈中,任何应用激活该Activity都会重用该栈中的实例并进入该应用中,即 多个应用共享该栈中实例
1.2 示意图
第一章 四大组件 之 Activity(一)_第11张图片
1.3 实例
通过测试发现,在第一次打开SingleInstanceActivity的时候,由于系统不存在该实例,所以系统会新建一个任务栈来存放该Activity实例,而且只要打开过一次该Activity,后面无论什么时候再次启动该Activity,都会直接引用第一次创建的实例,而且会回调该实例的onNewIntent()方法。
1.4场景
singleInstance适合需要与程序分离开的页面。例如闹铃提醒、电话拨号盘界面。

(5)启动模式总结

第一章 四大组件 之 Activity(一)_第12张图片
(1)standard
标准模式下,只要启动一次Activity,系统就会在当前任务栈新建一个实例。
(2)singleTop
1、当前栈中已有该Activity的实例并且该实例位于栈顶时,不会创建实例,而是复用栈顶的实例,并且会将Intent对象传入,回调onNewInten()方法;
2、当前栈中已有该Activity的实例但是该实例不在栈顶时,其行为和standard启动模式一样,依然会创建一个新的实例;
3、当前栈中不存在该Activity的实例时,其行为同standard启动模式。
(3)singleTask
在复用的时候,首先会根据taskAffinity去找对应的任务栈:
1、如果不存在指定的任务栈,系统会新建对应的任务栈,并新建Activity实例压入栈中。
2、如果存在指定的任务栈,则会查找该任务栈中是否存在该Activity实例
a、如果不存在该实例,则会在该任务栈中新建Activity实例。
b、如果存在该实例,则会直接引用,并且回调该实例的onNewIntent()方法。并且任务栈中该实例之上的Activity会被全部销毁。
(4)singleInstance
启动该模式Activity的时候,会查找系统中是否存在:
1、不存在,首先会新建一个任务栈,其次创建该Activity实例。
2、存在,则会直接引用该实例,并且回调onNewIntent()方法。
特殊情况:该任务栈或该实例被销毁,系统会重新创建。

在使用APP过程中,不可避免页面之间的跳转,那么就会涉及到启动模式。其实在对界面进行跳转时,Android系统既能在同一个任务中对Activity进行调度,也能以Task(任务栈)为单位进行整体调度。在启动模式为standard或singleTop时,一般是在同一个任务中对Activity进行调度,而在启动模式为singleTask或singleInstance是,一般会对Task进行整体调度。

(6)任务栈

(6.1)什么是任务栈

application中有很多activity,application是通过任务栈的形式对管理这些activity。任务栈有以下几个特点:

  • 任务栈是app管理activity的一种容器,遵循先进后出原则
  • 一个app默认只有一个任务栈,由系统指定
  • 一个app可以有多个任务栈,需要开发者手动指定
  • 多任务栈出栈(点击back)规则:出栈时,先将前台栈清空,再去清空后台栈

(6.2)taskAffinity

activity的任务栈的相关性。拥有相同affinity的activity在概念上属于同一个task。一个task的affinity取决于这个task内的根activity的taskaffinity。taskaffinity属性用于指定当前Activity所关联的任务栈,它的作用主要有:

  • 通过FLAG_ACTIVITY_NEW_TASK标记给activity指定任务栈
  • 决定Activity重新归属的任务(与allowTaskReparenting联合实现把一个应用程序的activity移到另一个程序的任务栈中)
    默认情况下,application中所有的activity拥有相同的affinity(application包名),可以通过给taskaffinity属性设置不同的值把他们分组。甚至可以把多个application中的activity放到同一个task中。如果这个属性没有被设置,那么此属性的值就继承自application的此属性的值(查看 application的taskaffinity属性)。默认的值为application的包名。
    举例:
    如果加载某个Activity的intent,Flag被设置成FLAG_ACTIVITY_NEW_TASK时,它会首先检查是否存在与自己taskAffinity相同的Task,如果存在,那么它会直接宿主到该Task中,如果不存在则重新创建Task。
    AndroidManifest



    
    
    

    
        
            
                

                
            
        

        

        

        
    


通过FLAG_ACTIVITY_NEW_TASK标记给activity指定任务栈
ActivityA

 tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(ActivityA.this,ActivityB.class);
                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//添加FLAG_ACTIVITY_NEW_TASK标识
                startActivity(i);
            }
        });

ActivityB

 tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(ActivityB.this,ActivityC.class);
                startActivity(i);//ActivityC为singleTask模式。singleTask模式启动时会给intent添加 FLAG_ACTIVITY_NEW_TASK 标记
            }
        });

可以清楚的看到,其中包含了三个任务栈:
第一个:栈名:example.ylh.com,栈id:8904,包含MainActivity和ActivityA。
第二个:栈名:example.ylh.com_task01,栈id:8905,包含ActivityB。
第三个:栈名:example.ylh.com_task02,栈id:8906,包含ActivityC。 结果符合我们的预期。到此,我们可以得出结论,使用taskAffinity和FLAG_ACTIVITY_NEW_TASK(或singleTask),可以做到给我们的activity指定相应的任务栈。

(6.2)allowTaskReparenting属性

当某个拥有相同 affinity 的任务即将返回前台时,Activity 是否能从启动时的任务转移至此任务中去 —“true”表示可以移动,“false”表示它必须留在启动时的任务中。
通常在启动时,Activity 与启动时的任务相关联,并在整个生命周期都位于此任务中。 利用本属性可以强行让 Activity 在当前任务不再显示时归属于另一个与其 affinity 相同的任务。 典型应用是让一个应用程序的 Activity 转移到另一个应用程序关联的主任务中去。
实例
如果该Activity的allowTaskReparenting设置为true,它进入后台,当一个和它有相同affinity的Task进入前台时,它会重新宿主,进入到该前台的task中。
应用A的activityA

public class ActivityA extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_test);

        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText("A");
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent();
                i.setClassName("ylh.bsdf.com","ylh.bsdf.com.ActivityC");
                startActivity(i);
            }
        });
    }
}

应用A的AndroidManifest




    
        
            
                
                
            
        

        
        
        
    


应用B的activityC

public class ActivityC extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.tv);
        tv.setText("app B activityC");
    }
}

应用B的AndroidManifest




    
        
            
                
                
            
        

        
        
    


首先,我们启动appA,加载ActivityC,然后按Home键,使该task(假设为task1)进入后台。然后启动appB,默认加载MainActivity。但是我们却看到了ActivityC。实际上MainActivity也被加载了,只是ActivityC重新宿主,所以看到了ActivityC。
应用
如果某条 e-mail 信息包含了一个 Web 页的链接,点击此链接将启动一个 Activity 显示此 Web 页。 这个 Activity 是由浏览器程序定义的,但却作为 e-mail 任务的一部分被启动。 如果它重新归属于浏览器的任务,那么在下次浏览器进入前台时就会显示出来,并且会在 e-mail 任务再次回到前台时消失。

(7)Android退出整个应用解决方案

1、利用SingTask

将主Activity设为SingTask模式,然后在要退出的Activity中转到主Activity,然后重写主Activity的onNewIntent函数,并在函数中加上一句finish

2、利用历史栈和SingleTop

我们知道Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在D窗口打开A窗口时在Intent中直接加入标志Intent.FLAG_ACTIVITY_CLEAR_TOP,再次开启A时将会清除该进程空间的所有Activity。
在D中使用下面的代码

Intent intent = new Intent(); intent.setClass(D.this, A.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  //注意本行的FLAG设置 
startActivity(intent); finish();关掉自己 

在A中加入代码

Override
protected void onNewIntent(Intent intent) { // TODO Auto-generated method stub
super.onNewIntent(intent);
//退出
        if ((Intent.FLAG_ACTIVITY_CLEAR_TOP & intent.getFlags()) != 0) {
               finish();
        }
}

A的Manifest.xml配置成

android:launchMode="singleTop"

原理总结: 一般A是程序的入口点,从D起一个A的activity,加入标识Intent.FLAG_ACTIVITY_CLEAR_TOP这个过程中会把栈中B,C,都清理掉。因为A是android:launchMode=”singleTop” 不会调用oncreate(),而是响应onNewIntent()这时候判断Intent.FLAG_ACTIVITY_CLEAR_TOP,然后把A finish()掉。 栈中A,B,C,D全部被清理。所以整个程序退出了。

3、通过广播来完成退出功能

具体实现过程是这样的:在每个Activity创建时(onCreate时)给Activity注册一个广播接收器,当退出时发送该广播即可。大概的代码如下:

@Override

protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       IntentFilter filter = new IntentFilter();
       filter.addAction("finish");
       registerReceiver(mFinishReceiver, filter)
       ……
}

private BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
           if("finish".equals(intent.getAction())) {
              Log.e("#########", "I am " + getLocalClassName()
                     + ",now finishing myself...");
              finish();
       }
    }
};

相信聪明的大家会把上面的代码写在一个基类里面,因为如果你的项目中Activity很多的话,写起来很麻烦,而且也不符合代码规范。
在退出时执行以下代码即可关闭所有界面完全退出程序:

getApplicationContext().sendBroadcast(new Intent("finish"));

4、使用退出类

现下最流行的方式是定义一个栈,写一个自定义的MyApplication类,利用单例模式去单独对Activity进行管理,在每个Activity的onCreate()方法中调用MyApplication.getInstance().addActivity(this)将当前的Activity添加到栈中统一管理,如果需要退出应用程序时再调用MyApplication.getInstance().exit()方法直接就完全退出了应用程序。
实现方案:统一管理的好处就是如果需要退出时,直接将add进栈的Activity进行同意finish就行。exit方法的实现原理就是将栈中所有的Activity实例循环然后finish的。
方式1:

public class CloseActivity
{
    private static LinkedList acys = new LinkedList();

    public static Activity curActivity;

    public static void add(Activity acy)
    {
        acys.add(acy);
    }

    public static void remove(Activity acy) {
        acys.remove(acy);
    }

    public static void close()
    {
        Activity acy;
        while (acys.size() != 0)
        {
            acy = acys.poll();
            if (!acy.isFinishing())
            {
                acy.finish();
            }
        }
//        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

方式2:
将下面SysApplication这个类复制到工程里面,然后在每个Acitivity的oncreate方法里面通过SysApplication.getInstance().addActivity(this); 添加当前Acitivity到ancivitylist里面去,最后在想退出的时候调用SysApplication.getInstance().exit();可直接关闭所有的Acitivity并退出应用程序。
附代码:

public class SysApplication extends Application { 
    private List mList = new LinkedList(); 
    private static SysApplication instance; 

    private SysApplication() {   
    } 
    public synchronized static SysApplication getInstance() { 
        if (null == instance) { 
            instance = new SysApplication(); 
        } 
        return instance; 
    } 
    // add Activity  
    public void addActivity(Activity activity) { 
        mList.add(activity); 
    } 

    public void exit() { 
        try { 
            for (Activity activity : mList) { 
                if (activity != null) 
                    activity.finish(); 
            } 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } finally { 
            System.exit(0); 
        } 
    } 
    public void onLowMemory() { 
        super.onLowMemory();     
        System.gc(); 
    }  
}

在应用程序里面 的activity的oncreate里面添加SysApplication.getInstance().addActivity(this)如:

public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SysApplication.getInstance().addActivity(this); 
}

总结:在程序内维护一个activity list,在响应应用程序退出的时候,遍历该list,调用每一个Activity的finish()方法

Android.os.Process.killProcess(android.os.Process.myPid())  

或者

System.exit(0)  

即可完全退出程序(进程也同时被杀死)。

(六)Activity现场保存状态

(1)场景

一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会得到保留.
有些内存不足、设备配置、意外操作可能会在运行时发生变化(例如屏幕方向、键盘可用性及语言设定切换而不是正常的应用程序行为)。 发生这种变化时,Android系统会破坏正在运行的 Activity。但系统会使用一组存储在Bundle对象中的键值对的集合来保存该Activity当前状态。这样如果用户导航回它,系统会创建一个新的Activity实例并使用一组保存的数据描述Activity被销毁的状态。从而回复之前"实例状态"。
要妥善处理重启行为,Activity 必须通过常规的Activity 生命周期恢复其以前的状态,在 Activity 生命周期中,Android 会在停止 Activity 之前调用 onSaveInstanceState(),以便您保存有关应用状态的数据。 然后,您可以在 onCreate()onRestoreInstanceState() 期间恢复 Activity 状态。

onSaveInstanceState()调用时刻
当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
注意上面的双引号,何为“容易”?言下之意就是该activity还没有被销毁,而仅仅是一种可能性。包括如下场景:

  • 锁屏
  • 点击home键
  • 其他app进入前台(接听电话)
  • 启动新Activity
  • 屏幕方向改变(在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行)
  • App被杀死(内存不足)

这些情况下Activity优先级较低,系统随时都有可能"未经你的允许"毁灭Activity。则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据。
onRestoreInstanceState()调用时刻
至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行

另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。

(2)原理

状态改变时,当前Activity被销毁(onDestroy)后重启一个全新的Activity(onCreate)(命令行输出hashcode不一致)导致之前Activity视图数据丢失。
默认情况下,系统使用Bundle实例状态来保存有关View中Activity布局每个对象的信息(例如输入到EditText对象中的文本值)。因此,如果Activity实例被异常销毁并重新创建,则布局状态会自动恢复到之前的状态。(注:只有有id的组件自动保存状态)
但是,Activity可能包含更多要恢复的状态信息,例如跟踪Activity中用户进度的成员变量。此时可以在activity被销毁之前调用保存每个实例的状态,开发者可以覆写onSaveInstanceState()方法(保存当前activity数据)和onRestoreInstanceState()(获取之前保存的数据在新activity恢复)添加需要额外保存的Activity信息。
onSaveInstanceState()方法接受一个Bundle类型的参数, 开发者可以将状态数据存储到这个Bundle对象(键值对形式,用于数据的保存和读取)中,以保证该状态在onCreate(Bundle)或者onRestoreInstanceState(Bundle)(传入的Bundle参数是由onSaveInstanceState封装好的)中恢复。
若向数据库中插入记录等,保存持久化数据的操作应该放在onPause()/onStop()中. onSaveInstanceState()方法只适合保存瞬态数据, 比如UI控件的状态, 成员变量的值等.

(3)生命周期

第一章 四大组件 之 Activity(一)_第13张图片

(4)源码

4.1)保存Activity状态

当您的Activity开始停止时,系统会调用,onSaveInstanceState()以便您的Activity可以使用一组键值对来保存状态信息。此方法的默认实现保存有关Activity视图层次结构状态的信息,例如EditText小部件中的文本或ListView的滚动位置。
为了保存Activity的附加状态信息,您必须实现onSaveInstanceState()并向对象添加键值对Bundle。例如:

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

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // 保存用户自定义的状态
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
    // 调用父类交给系统处理,这样系统能保存视图层次结构状态
    super.onSaveInstanceState(savedInstanceState);
}

4.2)恢复Activity状态

当您的Activity在之前被破坏后重新创建时,您可以从Bundle系统通过您的Activity中恢复您的保存状态。这两个方法onCreate()和onRestoreInstanceState()回调方法都会收到Bundle包含实例状态信息的相同方法。

4.2.1)在onCreate()方法中恢复Activity状态

因为onCreate()调用该方法是否系统正在创建一个新的Activity实例或重新创建一个以前的实例,所以必须Bundle在尝试读取之前检查该状态是否为空。如果它为空,那么系统正在创建一个Activity的新实例,而不是恢复之前被销毁的实例。
例如,下面是如何恢复一些状态数据onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // 记得总是调用父类
   
    // 检查是否正在重新创建一个以前销毁的实例
    if (savedInstanceState != null) {
        // 从已保存状态恢复成员的值
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // 可能初始化一个新实例的默认值的成员
    }
    ...
}
4.2.2)在onRestoreInstanceState()方法中恢复Activity状态

onRestoreInstanceState()只有在存在保存状态的情况下才会恢复,因此不需要检查是否Bundle为空:

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // 总是调用超类,以便它可以恢复视图层次超级
    super.onRestoreInstanceState(savedInstanceState);
   
    // 从已保存的实例中恢复状态成员
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

注:onRestoreInstanceState只有在activity被系统回收,重新创建activity的情况下才会被调用。
调用的例子
比如上期文章提到的onSaveInstanceState的第5种情况横竖屏切换:
onPause -> onSaveInstanceState -> onStop -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume
在这里onRestoreInstanceState被调用,是因为屏幕切换时原来的activity被系统回收了,又重新创建了一个新的activity。
不会被调用的例子
而按HOME键返回桌面,又马上点击应用图标回到原来页面时,activity生命周期如下:
onPause -> onSaveInstanceState -> onStop -> onRestart -> onStart -> onResume
因为activity没有被系统回收,因此onRestoreInstanceState没有被调用。
如果onRestoreInstanceState被调用了,则页面必然被回收过,则onSaveInstanceState必然被调用过。
由于Activity未被销毁,Activity实例仍然存在于内存中,Activity的所有信息和状态数据不会消失, 当Activity重新回到前台之后, 所有的改变都会得到保留.
onCreate()里也有Bundle参数,可以用来恢复数据,它和onRestoreInstanceState有什么区别?
因为onSaveInstanceState 不一定会被调用,所以onCreate()里的Bundle参数可能为空,如果使用onCreate()来恢复数据,一定要做非空判断。
而onRestoreInstanceState的Bundle参数一定不会是空值,因为它只有在上次activity被回收了才会调用。

(5)补充

5.1)如何避免配置改变时Activity重启?

在清单文件下每个activity注册时写上

android:configChanges=“XXX”

比如横竖屏切换:android:configChanges=“orientation”

你可能感兴趣的:(Android学习之旅,Android,Activity)