zoukankan      html  css  js  c++  java
  • Android 消息处理机制

    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);
        }
    }
    View Code

    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);
        }
    }
    View Code

     测试结果:

    /*每当点击屏幕上的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
    View Code

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

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

    参考:

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

  • 相关阅读:
    Delphi ini文件结构简介
    Delphi 格式化函数 Format函数
    Delphi 获取系统的语言环境参数GetSystemDefaultLangID、VerLanguageName、GetLocaleInfo
    Delphi DBGrid 实现复选框
    SQL 循环语句几种写法
    Delphi 左键代替右键
    CSV (逗号分隔值文件格式)
    中国人工智能AI框架自主研发
    电动汽车:不是如果,而是什么时候和多快
    KITTI数据集上MaskRCNN检测效果示例
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10801429.html
Copyright © 2011-2022 走看看