Skip to main content
 首页 » 编程设计

Android 消息处理机制

2022年07月19日50xiaohuochai

1.消息处理机制简介

主要用于进程内线程之间的通信,主线程一般调用looper()进行循环等待处理消息,其它线程向它发消息并指定消息的处理方法

(1)涉及文件包括frameworks中的:

Looper.java 
Handler.java 
MessageQueue.java 
Message.java 
android_os_MessageQueue.cpp 
...

涉及文件包括system中的:

Looper.h 
Looper.cpp

(2)涉及native处理机制
使用pipe加epoll机制实现消息队列的睡眠和唤醒进程的功能,同时利用epoll的timeout特性可以指定消息延期多长时间后执行。

2.消息发送流程

enqueueMessage    //MessageQueue.java 
    nativeWake(mPtr); 
        android_os_MessageQueue_nativeWake //android_os_MessageQueue.cpp 
            nativeMessageQueue->wake() 
            wake() //system/core/libutils/Looper.cpp 
                 write(mWakeWritePipeFd, "W", 1); //只是向消息队列的写端写入一个字符唤醒epoll_wait监听而已

从发送流程可以看出:
Framework中的sendMessage其实并不是通过管道传输的,它只是把msg放到Looper的消息队列上,获取消息的时候是直接从消息队列上获取的,
整个消息传送的过程根本不涉及管道传输数据。native方法中使用pipe进行epoll的作用仅仅是想让java的队列具有睡眠唤醒功能

3.消息获取流程

loop() //Looper.java 
    queue.next() //MessageQueue.java 
        nativePollOnce(ptr, nextPollTimeoutMillis); //会阻塞在这个函数它,它最终调用的是epoll_wait()进行阻塞。 
            android_os_MessageQueue_nativePollOnce //android_os_MessageQueue.cpp 
                pollOnce(int timeoutMillis) //system/core/include/utils/Looper.h 
                    pollInner //system/core/libutils/Looper.cpp 
                        epoll_wait(..., timeoutMillis); //调用系统的epoll_wait函数并设置等待时间为timeoutMillis

4.消息的处理流程

Handler.java中的dispatchMessage方法:

public void dispatchMessage(Message msg) { 
    //优先调用callback,注意它是一个Runnable线程!!执行结果就是启动这个线程去执行。 
    if (msg.callback != null) { 
        handleCallback(msg); 
    } else { 
        //否则若是创建handler的时候指定了callback,就调用这个callback的handleMessage()进行处理 
        if (mCallback != null) { 
            if (mCallback.handleMessage(msg)) { 
                return; 
            } 
        } 
        //否则就调用handler的它,它是个空函数,但是可以被重写 
        handleMessage(msg); 
    } 
}

5.实验Demo

下面的例子是分别使用这三种处理msg的方法的Demo,在MainActivity.java中实现的

package com.example.mm.app_message_01; 
 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Looper; 
import android.os.Message; 
import android.support.design.widget.FloatingActionButton; 
import android.support.design.widget.Snackbar; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 
import android.util.Log; 
import android.view.View; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.widget.Button; 
 
public class MainActivity extends AppCompatActivity { 
 
    private static final String TAG = "MessageTest"; 
    private Button mButton = null; 
    private int mClickedCount = 0; 
    private int getMessageCount1 = 0; 
    private int getMessageCount2 = 0; 
    private int getMessageCount3 = 0; 
 
    /* Test1: success */ 
    private MyThread mThread1 = null; 
    private Handler mHandler1 = null; 
 
    private MyThread mThread2 = null; 
    private Handler mHandler2 = null; 
 
    private MyThread mThread3 = null; 
    private Handler mHandler3 = null; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        Toolbar toolbar = findViewById(R.id.toolbar); 
        setSupportActionBar(toolbar); 
 
 
        mButton = (Button) findViewById(R.id.button); 
        mButton.setOnClickListener(new View.OnClickListener() { 
            public void onClick(View v) { 
                // Code here executes on main thread after user presses button 
                Log.d(TAG, "Clicked: " + mClickedCount); 
                mClickedCount++; 
 
                mHandler1.sendMessage(new Message()); 
 
                mHandler2.post(new Runnable() { 
                    @Override 
                    public void run() { 
                        Log.d(TAG, "-2-: Get a new Message, getMessageCount = " + getMessageCount2); 
                        getMessageCount2++; 
                    } 
                }); 
 
                mHandler3.sendMessage(new Message()); 
            } 
        }); 
 
        /*----------------------test1------------------------*/ 
        mThread1 = new MyThread(); 
        mThread1.start(); 
        mHandler1 = new Handler(mThread1.getLooper(), new Handler.Callback() { 
            @Override 
            public boolean handleMessage(Message msg) { 
                Log.d(TAG, "-1-: Get a new Message, getMessageCount = " + getMessageCount1); 
                getMessageCount1++; 
                return true; 
            } 
        }); 
 
        /*----------------------test2------------------------*/ 
        mThread2 = new MyThread(); 
        mThread2.start(); 
        mHandler2 = new Handler(mThread2.getLooper()); 
 
        /*----------------------test3------------------------*/ 
        mThread3 = new MyThread(); 
        mThread3.start(); 
        mHandler3 = new MyHandler(mThread3.getLooper()); 
    } 
 
    class MyThread extends Thread { 
        private Looper mLooper; 
 
        public void run() { 
            Looper.prepare(); 
            synchronized (this) { 
                mLooper = Looper.myLooper(); 
                notifyAll(); 
            } 
            Looper.loop(); 
        } 
        Looper getLooper() { 
            if (!isAlive()) { 
                return null; 
            } 
            synchronized (this) { 
                if (mLooper == null) { 
                    try { 
                        wait(); 
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
                } 
            } 
            return mLooper; 
        } 
    } 
 
    class MyHandler extends Handler { 
        public MyHandler(Looper looper) { 
            super(looper); 
        } 
        @Override 
        public void handleMessage(Message msg) { 
            Log.d(TAG, "-3-: Get a new Message, getMessageCount = " + getMessageCount3); 
            getMessageCount3++; 
        } 
    } 
 
    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
        // Inflate the menu; this adds items to the action bar if it is present. 
        getMenuInflater().inflate(R.menu.menu_main, menu); 
        return true; 
    } 
 
    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
        // Handle action bar item clicks here. The action bar will 
        // automatically handle clicks on the Home/Up button, so long 
        // as you specify a parent activity in AndroidManifest.xml. 
        int id = item.getItemId(); 
 
        //noinspection SimplifiableIfStatement 
        if (id == R.id.action_settings) { 
            return true; 
        } 
 
        return super.onOptionsItemSelected(item); 
    } 
}

测试结果:

/*每当点击屏幕上的Button都会打印下面一组log:*/ 
01-01 13:15:22.310 13412-13412/com.example.mm.app_message_01 D/MessageTest: Clicked: 14 
01-01 13:15:22.312 13412-13431/com.example.mm.app_message_01 D/MessageTest: -1-: Get a new Message, getMessageCount = 14 
01-01 13:15:22.312 13412-13432/com.example.mm.app_message_01 D/MessageTest: -2-: Get a new Message, getMessageCount = 14 
01-01 13:15:22.312 13412-13433/com.example.mm.app_message_01 D/MessageTest: -3-: Get a new Message, getMessageCount = 14

6.native的实现很复杂,好像是镜面映射了一个message的queue和java的queue对应。

7.Looper类中只有一个构造函数,它里面new了一个MessageQueue,也就是说MessageQueue是Looper对象的。

参考:

android消息处理机制原理解析:https://blog.csdn.net/chunqiuwei/article/details/52251242


本文参考链接:https://www.cnblogs.com/hellokitty2/p/10801429.html