android 之 Handler 详解----(一)实现的消息传递基本原理(流程分析)

来源:互联网 发布:笔顺查询软件 编辑:程序博客网 时间:2024/05/18 01:55

          Handler可以说是android 中必需掌握的一个点,是android 提供的一套完整的消息传递的机制。我们常见的有用于 UI 的更新。

          近来对相关的源代码以及使用进行了了解,记录以下几点:

          (一)实现的基本原理

          (二)常见的使用的基本方式

          (三)更新UI的方法


(一)实现的消息传递基本原理(流程分析)

    Handler 实现的离不开Looper 以及 MessageQueue,总结来说是:

       1.Handler负责消息的发送,Looper负责接收Handler发送的消息,并且直接回传给Handler自己来处理消息。

       2.Looper创建的时候会关联一个MessageQueue 的一个存储消息的容器,负责消息的存储。


       以下是以main 线程(UI线程)的handler 以及 Looper为例,讲解一下handler消息是如何传递的。

       主要的流程如下:

       线程创建-----> Looper的创建 ----> handler 与 Looper的关联----->handler 发送消息----->通过Looper以及messageQueue----->回传给自己handler自己处理消息。

       下面是详细的流程讲解:

            (首先看看以下简单的handler的使用代码)

         <例子>

public class MainActivity extends Activity {//UI线程中的handler处理private Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {if (msg.what == 1) {System.out.println("main thread-----UI thread");}};};    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //子线程        new Thread(){        @Override        public void run() {            Message msg = new Message();            msg.what = 1 ;            //通过主线程的handler对象,发消息回自己处理            handler.sendMessage(msg);        }        }.start();    }}

           在一个线程中,使用handler 必须要创建相关联的 Looper 来一起使用,不然系统会抛出异常。那为什么在main线程(UI线程)中没有Looper的相关操作呢?其实在main线程(UI线程)在其创建的时候,就已经对looper进行的操作,我们在源代码中查看一下:

           <A> . ActivityThread.java中的main函数如下:

        Looper.prepareMainLooper();        if (sMainThreadHandler == null) {            sMainThreadHandler = new Handler();        }        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();

          主线程在在创建的时候,其中的main方法调用的时候,已经对Looper进行了关联,下面我们跟踪进
入Looper.prepareMainLooper,进入到prepareMainLooper,里面,发现里面有个prepare 方法,以下是prepare()方法的具体代码:

          < B > Looper.java

public static void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper();    }    public static void prepareMainLooper() {        prepare();        setMainLooper(myLooper());        myLooper().mQueue.mQuitAllowed = false;    }    private synchronized static void setMainLooper(Looper looper) {        mMainLooper = looper;    }
         在进入looper之中,prepare方法新建了一个 Looper ,然后后面给了mMainLooper,这个时候main线程中的Looper已经准备好了,准备好了,后面就可以使用了。

         而在 new  Looper()中,还创建了一个MessageQueue:

private Looper() {        mQueue = new MessageQueue();        mRun = true;        mThread = Thread.currentThread();    }
       

到此为止,UI线程中已经建立了Looper 以及messageQueue了。
     


      在我们的事例代码中,有中new Handler的操作,深入源代码中,查找,里面会发现,里面就是和相应的Looper进行了关联,也关联相关的MessageQueue,Handler中的构造函数:

          < C >  Handler.java

mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = null;

       

       <例子>中UI线程新建一个handler 的操作,实际也和Looper而进行了关联,然后在oncreate中新建一个线程,通过handler中的sendMessage()方法进行消息的发送操作,下面就开始看看,消息是如何发送回来 handler自身的。

         < D >... Handler.java    MessageQueue.java

    public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }    public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }    public boolean sendMessageAtTime(Message msg, long uptimeMillis)    {        boolean sent = false;        MessageQueue queue = mQueue;        if (queue != null) {            msg.target = this;            sent = queue.enqueueMessage(msg, uptimeMillis);        }        else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;    }


        消息已经保存到了MessageQueue中去了,然后Looper的作用就开始了,Looper就是要把MessageQueue中的消息轮询的方式发送出去,

        往回看一下  <A>  中的代码,最后的时候,调用了 Looper.loop(),这个作用到底是什么呢?没错,这个就是Looper要传消息了,我们深入看看其中的代码:

        <E>  Looper.java

public static void loop(){        Looper me = myLooper();        ...        MessageQueue queue = me.mQueue;                ...                while (true) {            Message msg = queue.next(); // might block            if (msg != null) {            ...                msg.target.dispatchMessage(msg);               ...                             msg.recycle();            }        }    }



           上面的代码重点在 轮询 messageQueue里面的message ,然后就是调用msg.target.dispatchMessage(msg), 这个就会发现这个消息回传到了UI线程中的handler了大笑

           <F> Handler.java

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

           这个时候,消息就重新发回到handler自身的handleMessage 方法中了,消息大功告成的传了回来。


      上面是叙述了UI线程中的handler消息的回传的流程,一样的如果我们需要在一个新建的线程中,创建一个handler 来接收其他线程或者UI线程传过来的消息,必须对 Looper进行操作,Looper.prepare()以及Looper.loop()的操作,不然与这个线程不能关联到。UI线程中,只是预先帮我们做了。 当然其实还有另外的方法不用我们自己手动进行,而且可以更加的安全,那个就是HandlerThread,这个后续我关于Handler的使用的帖子,对此进行记录,我的学习状态。


       原创,如需转载请标明出处,谢谢~

0 0
原创粉丝点击