深入理解Android生命周期

深入理解Android生命周期

面试时候常常被问到特别是Activity的生命周期 是怎样的,初学者仅仅会从简单的onCreate、onR esume等方法入手。向面试官介绍这些回调方法执 行的顺序,更好一点的会提到任务栈,或者是启 动模式,以为自己答的不错,而却不知道那仅仅 是皮毛而已。

在陈述之前,我想知道你是否对HandlerLooper、以及MessageQueue有落了解。这可是面试官必考的问题之一。
如果看过相关的源码,你得了解以下的几条关于这几个类的信息。

通过Handler我们可以从子线程向主线程发送消息,即所谓的更新UI。
Looper 是个消息循环,不断从MessageQueue中取出消息,交给对应Handler处理。

在主线程中创建的Hander的执行过程是在主线程,如果想要Hander处理在子线程,请使用HandlerThread来创建,或者使用从子线程中创建的Handler。子线程必须实现一个Looper消息循环。

你真的了解主线程吗?

所有的Java应用程序都是从main方法开始的,我说的没错吧,对于Java桌面程序或者JEE Servlet 容器。我想说,是 Android应用也是从Main 方法开始的。
当Android系统启动的时候,它会启动一个叫 ZygoteInit 的进程,这个进程就是一个 Dalvik VM。进程会在一个线程里面加载SDK相关的类,并处于等待状态,这里我不多说,我也就提一嘴这个进程。

当你启动一个Android应用的时候,Android系统会fork上面那个ZygoteInit进程。fork之后的那子进程的对应的那个线程(就是上面提到加载SDK后等待的线程)会停止等待,并调用ActivityThread.main()

image

Loopers

Loopers 存在目的,就是为了能让一个线程顺序的处理消息事件。

每一个Looper的内部拥有一个队列,叫MessageQueue,里面存放这个各种消息对象Message

Looper拥有loop()方法,方法里面按顺序处理队列(MessageQueue)里面的消息,如果队列为空,那么就会等待。

Looper.loop() 内部实现也是很简单

void loop() {
    while(true) {
        Message message = queue.next();// block if empty
        dispatchMessage(message);
        message.recycle();
    }
}

每一个Looper都与一个线程相关联。创建一个Looper并将其与当前线程相关联,你必须在线程里面调用 Looper.prepare()方法,创建好的Looper会放在ThreadLocal里面,你可以通过Looper.myLooper()方法得到与当前线程关联的 Looper 对象,另外
这也使得这个线程变成了一个 Pipline线程

HandlerThread 类内部就相当于创建一个上述 Pipline线程。通过HandlerThread你无须自己创建 Looper。并直接可以从中获取Looper对象,通过这个Looper对象和Handler你可以向这个线程发消息进行让它处理,这样处理是在子线程中进行的。

HandlerThread thread = new HandlerThread("handlerthread");
thread.start();// 启动这个线程
Looper looper = thread.getLooper();

Handlers

Handler 肯定是要配合Looper来使用的,handler存在的作用在 在任何线程中通过Handler把消息放进Looper里面的消息队列当中处理任何从Looper取出的消息,但处理线程就是与Looper相关联的线程。

Handler handler = new Handler(looper) {
    public void handleMessage(Message message) {
        // 在与 looper 相关联的线程中处理消息
        if (message.what == DO_SOMETHING) {
            // do something
        }
    }
}

// 创建消息对象
Message message = handler.obtainMessage(DO_SOMETHING);
handler.sendMessage(message);

多个Handler 可以绑定同一个Looper对象,让后Looper 会分发消息给message.target

Handler还有一种用法是传递一个Runable对象。

handler.post(new Runnable() {
   public void run() {
    // 运行在looper相关联的线程
   }
});

一个Handler创建可以不用传递给它Looper对象

// 最好明确告诉它使用哪个Looper
Handler handler = new Handler();

对于Handler的无参数的构造函数,它会调用Looper.myLooper()并且得到与当前线程相关联的Looper对象,这就导致整个Looper可能不是你想要的那个Looper,所以最好还是应该传递给它一个明确的Looper

大多数情况下,我们需要主线程的Looper

Handler handler = new Handler(Looper.getMainLooper());

回到我们提到的ActivtyThread.main()

在这里面它做了这样一件事

public class ActivityThread {
    public static void main(String... args) {
        Looper.prepare();
        Looper.setMainLooper(Looper.myLooper());
        // Post first message to the looper
        {...}
        Looper.loop();
    }
}

你看到了,整个main thread就是一个Pipline 线程,无限处理各种消息。它的第一件事情就是创建Application类,并且调用Application.onCreate()回调方法。

Android 主线程生命周期

先看一个与Activty生命周期相关的例子,处理配置变化,比如更改屏幕显示方向这个老生常谈的问题。我们知道如果我们想用代码改变屏幕的方向,只需使用Activity#setRequestedOrientation(int)方法。

当你一个Activity以竖屏打开之后,在onCreate里面调用setRequestedOrientation(int)方法的时候,它的回调方法调用是怎样的?

public class MyActivity extends Activity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate();
        Log.d("Square", "onCreate()");
        if (saveInstanceState == null) {
            Log.d("Square", "Requesting orientation change");
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
        }
    }

    protected void onResume() {
        super.onResume();
        Log.d("Square", "onResume");
    }

    protected void onPasue() {
        super.onPasue();
        Log.d("Square", "onPasue()");
    }

    protected void onDestory() {
        super.onDestory();
        Log.d("Square", "onDestory()")
    }

}

如果你熟悉 Android 生命周期 你或许会预测到打印出的Log

onCreate()
Requesting orientation change
onResume()
onPause()
onDestory()
onCreate()
onResume()

Android 内部是怎样处理Orientation变化的呢?

这里有一条必须明确: 对于因Orientation变化导致的Activity的重构,实际上是通过向咱们的Main Looper 发送了几条消息到 Looper内部的消息队列(MessageQueue)当中去。MessageQueue仅仅是一个单链表,每一个节点的 next 指向下一条消息。

所以更确切的说,请求设置Orientation改变的时候时候,会将 CONFIGURATION_CHANGEDRELAUNCH_ACTIVITY 消息发送到主线程的main looper内部的消息队列。随后会被取出按顺序处理。

Service 并不运行在后台线程

待补充..

猜你喜欢

转载自blog.csdn.net/qiaojun1234567/article/details/82191362