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方法。

时间: 2024-10-22 21:11:07

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

Android笔记三十四.Service综合实例二

综合实例2:client訪问远程Service服务 实现:通过一个button来获取远程Service的状态,并显示在两个文本框中. 思路:如果A应用须要与B应用进行通信,调用B应用中的getName().getAuthor()方法,B应用以Service方式向A应用提供服务.所以.我们能够将A应用看成是client,B应用为服务端,分别命名为AILDClient.AILDServer. 一.服务端应用程序 1.src/com.example.aildserver/song.aidl:AILD文

Android笔记二十四.Android基于回调的事件处理机制

如果说事件监听机制是一种委托式的事件处理,那么回调机制则与之相反,对于基于回调的事件处理模型来说,事件源和事件监听器是统一的,或者说事件监听器完全消失了,当用户在GUI控件上激发某个事件时,控件自己特定的方法将会负责处理该事件. 转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.View类的常见回调方法 为了使用回调机制来处理GUI控件上所发生的事件,需要为该组件提供对应的事件处理方法,而Java又是一种静态语言,我们无法为每个对象动态地添

Android笔记三十二.Android位置服务及核心API

一.位置服务概念 1.位置服务 位置服务(Location-Based Services,LBS),又称定位服务或基于位置的服务,融合了GPS定位.移动通信.导航等多种技术,提供了与个空间位置相关的综合应用服务. 2.GPS与网络位置提供器 Android平台支持提供位置服务的API,可以利用GPS(Global Positioning System,全球定位系统)和Network Location Provider(网络位置提供器)来获得用户的位置. (1)GPS相对来说更精确,但它只能在户外

【Unity 3D】学习笔记三十四:游戏元素——常用编辑器组件

常用编辑器组件 unity的特色之一就是编辑器可视化,很多常用的功能都可以在编辑器中完成.常用的编辑器可分为两种:原有组件和拓展组件.原有组件是编辑器原生的一些功能,拓展组件是编辑器智商通过脚本拓展的新功能. 摄像机 摄像机是unity最为核心组件之一,游戏界面中显示的一切内容都得需要摄像机来照射才能显示.摄像机组件的参数如下: clear flags:背景显示内容,默认的是skybox.前提是必须在render settings 中设置天空盒子材质. background:背景显示颜色,如果没

Android笔记(三十二) Android中线程之间的通信(四)主线程给子线程发送消息

之前的例子都是我们在子线程(WorkerThread)当中处理并发送消息,然后在主线程(UI线程)中获取消息并修改UI,那么可以不可以在由主线程发送消息,子线程接收呢?我们按照之前的思路写一下代码: package cn.lixyz.handlertest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import andr

Android笔记(十四) Android中的基本组件——按钮

Android中的按钮主要包括Button和ImageButton两种,Button继承自TextView,而ImageButton继承自ImageView.Button生成的按钮上显示文字,而ImageButton上则显示图片. 主要功能是在UI界面上生成一个按钮,当用户点击这个按钮时,出发一个OnClick事件来执行某项任务. 简单示例 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"

Android笔记(七十四) 详解Intent

我们最常使用Intent来实现Activity之间的转跳,最近做一个app用到从系统搜索图片的功能,使用到了intent的 setType 方法和 setAction 方法,网上搜索一番,发现实现转跳只是Intent功能的九牛一毛,现在对Intent功能做一个总结,以作备忘. 我们经常使用如下方法实现一个转跳: Intent intent = new Inent(MainActivity.this,SecondActivity.class); startActivity(intent); 其实这

Android之旅十四 android中的xml文件解析

在我们做有关android项目的时候,肯定会涉及到对xml文件的解析操作.以下给大家介绍一下xml文件的解析.包括DOM.SAX.Pull以及曾经我们用到的DOM4J和JDOM: 要解析的XML文件:person.xml <? xml version="1.0" encoding="UTF-8"? > <persons> <person id="001"> <name>zhangsan</na

Android笔记二十五.Android事件Handler消息传递机制

因为Android平台不同意Activity新启动的线程訪问该Activity里的界面控件.这样就会导致新启动的线程无法动态改变界面控件的属性值.但在实际Android应用开发中,尤其是涉及动画的游戏开发中,须要让新启动的线程周期性地改变界面控件的属性值,这就须要借助Handler的消息传递机制实现. 一.Handler类简单介绍 1.功能 Handler类主要有两个作用 (1)在新启动的线程中发送消息; (2)在主线程中获取消息.处理消息.即当须要界面发生变化的时候.在子线程中调用Handle