从android源码分析Handler流程

执行prepareMainLooper

ActivityThread的main方法是app的入口,首先调用了Looper.prepareMainLooper();查看源码:

public static void prepareMainLooper() {
    
    
    prepare(false);
    synchronized (Looper.class) {
    
    
        if (sMainLooper != null) {
    
    
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

首先调用了Looper.prepare方法,该方法新建了一个Looper对方并放入ThreadLocal中,绑定了相应的线程(在这是主线程):

private static void prepare(boolean quitAllowed) {
    
    
    if (sThreadLocal.get() != null) {
    
    
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

然后执行了sMainLooper = myLooper();,将sMainLooper赋值为当前线程的Looper(在这是主线程的Looper)

public static @Nullable Looper myLooper() {
    
    
    return sThreadLocal.get();
}

由此可见,一个线程只有一个绑定的Looper对象,该Looper对象有ThreadLocal来保证线程绑定,同时别的线程需要调用主线程的Looper对象时,可以直接调用Looper.getMainLooper:

public static Looper getMainLooper() {
    
    
    synchronized (Looper.class) {
    
    
        return sMainLooper;
    }
}

获取Hnadler对象

回到ActivityThread的main方法中,执行完Looper.prepareMainLooper();后,

会获取AcitivityThread对应的Handler对象:sMainThreadHandler = thread.getHandler();

ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);

if (sMainThreadHandler == null) {
    
    
    sMainThreadHandler = thread.getHandler();
}

查看getHandler方法:

final Handler getHandler() {
    
    
    return mH;
}

mH在编译阶段已经赋值final H mH = new H();,H类是ActivityThread的内部类,继承自Handler,

class H extends Handler {
    
    
	public void handleMessage(Message msg) {
    
    
        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
        switch (msg.what) {
    
    
            case BIND_APPLICATION:
			......
            case EXIT_APPLICATION:
                if (mInitialApplication != null) {
    
    
                    mInitialApplication.onTerminate();
                }
                //注意这里的quit方法,执行完这个方法,Looper循环才真正结束
                Looper.myLooper().quit();
                break;
            case BIND_SERVICE:
            	......
	    }
	}
}

可见,ActivityThread对应的Handler对象处理了和app相关信息(Message)的对应措施

执行Looper.looper()

回到ActivityThread中,执行完sMainThreadHandler = thread.getHandler();后,执行Looper.looper():

public static void loop() {
    
    
    final Looper me = myLooper();
	......
        
    final MessageQueue queue = me.mQueue;
	......
        
    for (;;) {
    
    
        Message msg = queue.next(); // might block
        if (msg == null) {
    
    
            // No message indicates that the message queue is quitting.
            return;
        }
		......
        
        msg.target.dispatchMessage(msg);
        ......
            
    }
}

首先将线程对应的Looper对象赋值给me,然后将me中的MessageQueue赋值给queue,查看Looper的mQueue字段,该字段的初始化赋值在Looper对象的构造函数中

private Looper(boolean quitAllowed) {
    
    
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

也就是在最开始调用Looper.prepare的时候初始化Looper:sThreadLocal.set(new Looper(quitAllowed));

继续回到loop方法,给me和queue赋值后,执行了:

for (;;) {
    
    
    Message msg = queue.next(); // might block
    if (msg == null) {
    
    
        // No message indicates that the message queue is quitting.
        return;
    }

该for语句持续等到msg的到来,如果没有msg则无线循环,负责执行对应的msg,那么主线程持续的循环,是否会影响执行别的任务?回答是不会,查看queue.next方法:

Message next() {
    
    
	......
	
    int nextPollTimeoutMillis = 0;
    for (;;) {
    
    
        if (nextPollTimeoutMillis != 0) {
    
    
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);
		......
		
    }
}

ptr是MessageQueue初始化的native方法得到

MessageQueue(boolean quitAllowed) {
    
    
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

looper循环机制

对于next方法,最重要的是native方法, nativePollOnce(ptr, nextPollTimeoutMillis),参考知乎镰仓评论 (1):

A. Android应用程序的消息处理机制由消息循环、消息发送和消息处理三个部分组成的。
B. Android应用程序的主线程在进入消息循环过程前,会在内部创建一个Linux管道(Pipe),这个管道的作用是使得Android应用程序主线程在消息队列为空时可以进入空闲等待状态,并且使得当应用程序的消息队列有消息需要处理时唤醒应用程序的主线程。
C. Android应用程序的主线程进入空闲等待状态的方式实际上就是在管道的读端等待管道中有新的内容可读,具体来说就是是通过Linux系统的Epoll机制中的epoll_wait函数进行的。
D. 当往Android应用程序的消息队列中加入新的消息时,会同时往管道中的写端写入内容,通过这种方式就可以唤醒正在等待消息到来的应用程序主线程。
E. 当应用程序主线程在进入空闲等待前,会认为当前线程处理空闲状态,于是就会调用那些已经注册了的IdleHandler接口,使得应用程序有机会在空闲的时候处理一些事情。

消息只能在某个具体的Looper上消耗,因此每个Handler都会绑定一个Looper。但是多个Handler可以绑定同一个Looper(这也是在主线程中能够创建新的Handler的原因)。

总结:

  1. app启动的方法是ActivityThread,这个不是一个线程,只是一个带有Thread的类
  2. 一个线程只对应一个Looper,需要在线程中执行Looper.prepare(),该方法会新建一个Looper并赋值到ThreadLocal中作为线程唯一的Looper,同时Looper在新建的时候也会新建一个MessageQueue,也就是说Looper和MessageQueue是线程相关的。
  3. 在执行Looper.loop()方法时,会知道对应线程的Looper,也就是sThreadLocal.get(),然后从Looper中得到对应线程的MessageQueue,从队列中不阻塞的拿出Message并处理
  4. 一个类(注意和Looper、MessageQueue线程相关的区别)对应一个Handler,也就是说对于一个A类,它自己内部维护这一个AHandler对象,其他线程需要把信息发送给A所生成的对象,必须要先获得AHandler对象,然后调用AHandler.handleMessage()就可以实现线程间的数据传输。
//主线程向子线程发送信息
public class MainActivity extends AppCompatActivity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final MyThread thread = new MyThread();
        thread.start();

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Message message = Message.obtain();
                message.what = 2;
                thread.handler.sendMessage(message);
            }
        });
    }

    class MyThread extends Thread{
    
    
        private Handler handler;

        @Override
        public void run() {
    
    
            super.run();
            Looper.prepare();
            handler = new Handler(){
    
       //handler必须在在线程的run方法中创建
                @Override
                public void handleMessage(Message msg) {
    
    
                    super.handleMessage(msg);
                    Toast.makeText(MainActivity.this,"MyThread handler 收到消息 :"+msg.what,Toast.LENGTH_LONG).show();
                }
            };
            Looper.loop();
        }
    }
}
//子线程给子线程发送信息自己实现
public class MainActivity extends AppCompatActivity {
    
    
    MyThread myThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.Button).setOnClickListener(v -> {
    
    
            new OtherThread().start();
        });
        myThread = new MyThread();
        myThread.start();
    }

    class MyThread extends Thread {
    
    
        Handler handler;

        @SuppressLint("HandlerLeak")
        @Override
        public void run() {
    
    
            Looper.prepare();
            handler = new Handler() {
    
    
                @Override
                public void handleMessage(Message msg) {
    
    
                    Toast.makeText(MainActivity.this, "this is MyThread.", Toast.LENGTH_SHORT).show();
                }
            };
            Looper.loop();
        }
    }

    class OtherThread extends Thread {
    
    

        @Override
        public void run() {
    
    
            super.run();
            Message message = new Message();
            message.arg1 = 10294;
            myThread.handler.sendMessage(message);
        }
    }
}

HandlerThread

HandlerThread使用步骤一般是:

//1. 创建实例对象
HandlerThread handlerThread = new HandlerThread("downloadImage");

//2. 启动HandlerThread线程
handlerThread.start();

//3. 构建循环消息处理机制
class ChildCallback implements Handler.Callback {
    
    
    @Override
    public boolean handleMessage(Message msg) {
    
    
        //在子线程中进行相应的网络请求

        //通知主线程去更新UI
        mUIHandler.sendMessage(msg1);
        return false;
    }
}

//4. 构建异步handler
Handler childHandler = new Handler(handlerThread.getLooper(),new ChildCallback());

HandlerThread就是一个线程,该线程拥有类似主线程类似的消息处理机制,和主线程的区别在于前者是APP启动就存在的线程,这个线程只有开发者需要做一些耗时等操作的时候会调用,同时主线程主要执行一些UI更新的操作(需要保证同步,如果UI更新操作是不同的线程执行有同步错误的风向),不适合做一些耗时的操作,因此需要使用HandlerThread来执行。

接下里分析HandlerThread四个步骤和普通的Handler机制的关系:

因为HandlerThread本质上是一个线程,该类继承自Thread,因此需要声明线程名和开启线程。开启线程后执行run方法

@Override
public void run() {
    
    
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
    
    
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

run方法中执行了类似主线程中的Looper.prepare()和Looper.loop()方法(onLooperPrepared方法是一个空方法,用来指定别的初始化操作)

第三步声明了继承自Handler.Callback的ChildCallback类,该类执行了重写了handleMessage方法,然后第四步新建了Handler类。查看Handler构造方法

public Handler(@NonNull Looper looper, @Nullable Callback callback) {
    
    
    this(looper, callback, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    
    
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

因为Looper类是线程绑定的,所以第四步中入参是handlerThread.getLooper(),第二个回调入参也是Handler类的成员变量,查看该变量的作用

public void dispatchMessage(@NonNull Message msg) {
    
    
    if (msg.callback != null) {
    
    
        handleCallback(msg);
    } else {
    
    
        if (mCallback != null) {
    
    
            if (mCallback.handleMessage(msg)) {
    
    
                return;
            }
        }
        handleMessage(msg);
    }
}

上述已经介绍了,dispatchMessage方法在Looper.loop()中使用,也就是说,系统一直轮循MessageQueue,如果队列中有消息,则分发消息处理,同时分发后具体的处理步骤有回调方法mCallback.handleMessage(msg)保证,理解这点,再回去看普通的Handler为什么可以直接重写handleMessage方法

public Handler() {
    
    
    this(null, false);
}

第一个null就是回调函数

public Handler(@Nullable Callback callback, boolean async) {
    
    
	......
    mCallback = callback;
}

对于Handler初始化之后,mCallback是个null,而Handler类中定义了handleMessage方法

public void handleMessage(@NonNull Message msg) {
    
    
}

Handler中为什么会有post(Runnable runnable)?

mHandler.post(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        //需要运行的代码
    }
})

查看post方法

public final boolean post(@NonNull Runnable r) {
    
    
   return  sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
    
    
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

查看dispatchMessage可知,最开始会查看Message中有没有Runnable,有的话直接执行handleCallback(msg)

private static void handleCallback(Message message) {
    
    
    message.callback.run();
}

如果不在Handler初始化的时候传入回调函数,则执行Handler类中的handlerMessage,否则执行mCallback.handleMessage(msg),因此也可以使用以下步骤实现第三步

Handler childHandler = new Handler(handlerThread.getLooper()) {
    
    
    @Override
    public void handleMessage(@NonNull Message msg) {
    
    
        super.handleMessage(msg);
    }
};

总结:对于消息来说,有三种处理机制,优先使用Message中的回调函数,通过mHandler.post(Runnable)传入,然后封装到Message中。其次使用初始化Handler传入的回调函数Handler childHandler = new Handler(handlerThread.getLooper(), new ChildCallback()),最后选择新建Handler重写的handlerMessage方法。

注意:这里的Runnable对象也是一个回调函数,另一个是Handler的内部类Callback

异步执行

HandleThread执行的是异步操作,查看Handler构造函数

public Handler(@NonNull Looper looper, @Nullable Callback callback) {
    
    
    this(looper, callback, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    
    
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

初始化后明明是非异步操作,也就是mAsynchronous == false。为何?

HandleThread的run方法为什么需要唤醒线程notifyAll()

public void run() {
    
    
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
    
    
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

这里唤醒操作主要针对主线程新建Handler对象Handler handler = new Handler(handlerThread.getLooper())的getLooper方法,如果Looper为空或者线程未启动,则该线程阻塞,当run方法中执行了mLooper = Looper.myLooper(),就可以唤醒HandleThread线程了

public Looper getLooper() {
    
    
    if (!isAlive()) {
    
    
        return null;
    }
    
    // If the thread has been started, wait until the looper has been created.
    synchronized (this) {
    
    
        while (isAlive() && mLooper == null) {
    
    
            try {
    
    
                wait();
            } catch (InterruptedException e) {
    
    
            }
        }
    }
    return mLooper;
}

猜你喜欢

转载自blog.csdn.net/weixin_48968045/article/details/115311206