Android笔记(三十四) Android中线程之间的通信(六)Handle中的post()方法详解

         我们之前都是使用sendMessage()方法来发送消息,使用handleMessage来处理消息的,今天我们来看另外一种方法,先看代码:

package cn.lixyz.handlertest;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;


public class MainActivity extends Activity {

    private Button button;
    private Handler handler = new Handler();
    private TextView textView;


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

        textView = (TextView) findViewById(R.id.textView);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TestThread t = new TestThread();
                t.start();
            }
        });

    }

    class TestThread extends Thread {
        @Override
        public void run() {
            super.run();
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 5; i++) {
                        Log.d("TTTT", (i + 1) + " 秒");
                        try {
                            Thread.sleep(1000 * 1);
                            textView.setText("5秒后修改的内容");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }
                }
            };

            handler.post(r);
        }
    }

}
MainActivity.java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center"
        android:text="更改前"
        android:textSize="30sp" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:text="Send Message" />


</LinearLayout>
acitivit_main.xml

         点击按钮,运行结果:

         从代码中我们可以看到,我新建了一个线程,线程中创建了一个Runnable对象,这个Runnable对象中有修改UI的操作,然后使用调用了Handler的 post() 方法,那么我们就来看一下这个 post() 究竟是如何实现的。

         查看Handler的源代码,找到post()方法

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

         我们发现,其实post方法直接调用了一个延时发送消息的方法 sendMessageDelayed() ,只不过延时为0,继续找到 getPostMessage() 方法

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

         在上面的代码中,我们发现,getPostMessage方法内新获取了一个Message对象,并且将我们传入的Runnage对象赋值给了这个Message对对象的 callback 属性,然后将之返回

         所以说, post() 方法的本质就是将一个Runnable对象赋值给一个Message属性的 callback 属性,然后将这个Message对象放入到消息队列当中去

         而之前我们说过,Looper的 loop() 方法会循环的从消息队列中取出消息,那么这时候Looper是怎么工作的呢,找到Looper的 loop() 方法

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

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

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycle();
        }
    }

          和之前说的一样,loop()方法执行之后,同样的先拿到Looper对象,之后开始循环从消息队列中取出消息,执行到 msg.target.dispatchMessage(msg); 因为Message的 target 属性是 Handler 类型的,我们去看Handler的 despatchMessage 方法

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

          可见,先进对收取到的Message对象的 callback 属性进行判断,如果不为空,为调用 handleCallback 方法,查看 handleCallback 方法

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

            message.callback.run(); 直接调用了Runnable对象的 run() 方法,而不是创建一个新线程,然后再调用这个线程的start方法。

 

原文地址:https://www.cnblogs.com/xs104/p/4822783.html