处女男学Android(五)---Handler完结篇之Handler的post方法详解
2014-10-10 11:06
225 查看
前言
上一篇blog(处女男学Android(四)---Handler进阶篇之Handler、Looper、MessageQueue工作机制)介绍了关于Handler、Looper、MessageQueue的工作原理和源码分析,已经对Handler的整体工作过程有了一个较为深刻的了解,那么关于Handler还有一些重要的知识点,本篇就具体记录一下关于Handler的post方法的用法和工作原理。
一、boolean android.os.Handler.post(Runnable r)方法简介
google对post方法的介绍是这样的:
红色方框中的解释大致是这样的:
将Runnable对象添加到消息队列中,这个Runnable对象将运行在一个线程中,即Handler所依附的线程中。
关于参数的解释很简单:参数r将会被执行。
关于返回值的解释大致是这样的:
如果返回true,就说明了Runnable对象成功放进了消息队列中。如果返回false则表示失败,通常是因为该消息队列正在被处理。
看了上面的解释相信大家都会有疑问,我看完之后列出了以下几个问题:
1.上面说执行post方法是将Runnable对象放到消息队列,但消息队列放的都应该是消息对象,即:Message对象,这 里怎么成Runnable对象了?
2.参数传来的Runnable对象将会被执行,究竟是什么时候执行呢?怎么执行?
3.Looper从消息队列中取出放进去的Runnable对象之后,会做什么?
下面通过一个小例子先看一下post方法的用法和效果。这个例子和第二篇blog中的例子一模一样,即通过点击按钮来改变UI,而且是通过post方法去发送消息。
Layout代码(third.xml):
Activity代码:
下面看一下运行效果:
通过上面的效果图我们不难发现:
Runnable中的代码运行在了主线程,所以在主线程中修改UI也自然没问题了,但这其中的原因以及上面的三个问题我们有必要搞清楚,下面我们结合源码简单分析一下。
二、源码分析
首先,我们自然应该先看看post方法到底都干了些什么:
这里我们需要再看看getPostMessage这个方法:
对比一下上一篇blog中提到的handler的sendMessage源码:
到这里我们可以发现post方法和sendMessage方法差不多,都是给消息队列中发送一条消息而已,只不过sendMessage方法中,Message对象是我们自己创建好传进去的,而post方法则是在内部创建一个Message对象,只是将我们传进去的Runnable对象赋值给Message对象的callback属性之后之后再返回而已。下面问题来了:挖掘机技术到底哪家强?开个玩笑。问题应该是这样的,Looper取出了Message对象之后又做了什么?
回顾上一篇blog,其实是通过在loop()方法中,循环到当前的Message对象时,调用msg.target.dispatchMessage(msg)方法,target也就是一个handler对象,其实就是调用handler的dispatchMessage(msg)这个方法来处理取出的消息对象的,那么这里我们再贴一遍这个方法的源代码:
现在看到这段应该大致明白怎么回事了,上一篇我们没有给callback属性赋值,所以会执行handleMessage方法,但现在我们调用post方法的同时就将一个Runnable对象赋值给了Message的callback属性,所以这里我们自然会走if,下面看看handleCallback(msg)这个方法都做了什么:
到了这里想必大家都已经明白了,直接调用了Runnable的run()方法来运行。有线程基础的话应该很清楚,run()方法和start()方法的区别就在于run()方法不会开启新线程,而是在原有的线程中运行。下面针对开头提出的问题作出解释和更正:
1.上面说执行post方法是将Runnable对象放到消息队列,但消息队列放的都应该是消息对象,即:Message对象,这 里怎么成Runnable对象了?
其实最终放到消息队列的还是Message对象,只是将传进去的Runnable对象赋值给了Message对象的callback属性之后再放到消息队列的。
2.参数的Runnable对象将会被执行,究竟是什么时候执行呢?
看完了最后的一段源码,很明显是Looper取出Message对象之后交给了Handler的handleCallback(msg)方法去处理,也就是在这个方法中通过直接调用run()方法执行了Runnable中的代码。
3.Looper从消息队列中取出放进去的Runnable对象之后,会做什么?
这里需要更正的是放进去的不是Runnable对象,而是Message对象,原因见1。至于做了什么,原因见2。
解释完了之前的问题,也了解了post方法,我们发现这是发送消息的另一种方式,比通过handler的sendMessage要简单一些,并不用继续在主线程中去重写handleMessage(msg)方法,因为Runnable的代码块本身就运行在主线程中。
三、总结
本篇blog主要记录了与handler相关的post方法的使用方法和工作原理,对通过handler发送消息也多了一种选择,关于handler的所有内容到这里基本已经记录完毕,虽然很多地方我个人的理解还不是很到位,但通过阅读源码确实感觉到有很大的收获,剩下的就是时间和努力的问题(鄙人较笨)。后续的blog准备学习记录一些UI方面的知识,比如自定义View、适配器等等,我会继续努力的,争取早日拿下Android!
上一篇blog(处女男学Android(四)---Handler进阶篇之Handler、Looper、MessageQueue工作机制)介绍了关于Handler、Looper、MessageQueue的工作原理和源码分析,已经对Handler的整体工作过程有了一个较为深刻的了解,那么关于Handler还有一些重要的知识点,本篇就具体记录一下关于Handler的post方法的用法和工作原理。
一、boolean android.os.Handler.post(Runnable r)方法简介
google对post方法的介绍是这样的:
红色方框中的解释大致是这样的:
将Runnable对象添加到消息队列中,这个Runnable对象将运行在一个线程中,即Handler所依附的线程中。
关于参数的解释很简单:参数r将会被执行。
关于返回值的解释大致是这样的:
如果返回true,就说明了Runnable对象成功放进了消息队列中。如果返回false则表示失败,通常是因为该消息队列正在被处理。
看了上面的解释相信大家都会有疑问,我看完之后列出了以下几个问题:
1.上面说执行post方法是将Runnable对象放到消息队列,但消息队列放的都应该是消息对象,即:Message对象,这 里怎么成Runnable对象了?
2.参数传来的Runnable对象将会被执行,究竟是什么时候执行呢?怎么执行?
3.Looper从消息队列中取出放进去的Runnable对象之后,会做什么?
下面通过一个小例子先看一下post方法的用法和效果。这个例子和第二篇blog中的例子一模一样,即通过点击按钮来改变UI,而且是通过post方法去发送消息。
Layout代码(third.xml):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp" > <TextView android:id="@+id/tv_textView1" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1.0" android:gravity="center_horizontal|center_vertical" android:text="Text Example" android:textSize="15sp" /> <Button android:id="@+id/btn_button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="Change Text" /> </LinearLayout>
Activity代码:
package com.example.handlertest; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class ThirdActivity extends Activity { private Button button; private TextView textView; private Handler handler = new Handler(); //在主线程定义一个handler @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.third); textView = (TextView) findViewById(R.id.tv_textView1); button = (Button) findViewById(R.id.btn_button1); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { MyThread mThread = new MyThread(); mThread.start(); //启动MyThread } }); } class MyThread extends Thread { @Override public void run() { handler.post(new Runnable() { //通过post方法发送消息 @Override public void run() { String currentThreadName = Thread.currentThread().getName(); System.out.println("当前线程名称为--->" + currentThreadName); //打印线程名 try { Thread.sleep(1000 * 2); // 模拟一个2s的耗时任务 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } String s = "\n has been changed !"; textView.setText(textView.getText() + s); textView.setTextColor(Color.RED); // 更改UI } }); } } }
下面看一下运行效果:
通过上面的效果图我们不难发现:
Runnable中的代码运行在了主线程,所以在主线程中修改UI也自然没问题了,但这其中的原因以及上面的三个问题我们有必要搞清楚,下面我们结合源码简单分析一下。
二、源码分析
首先,我们自然应该先看看post方法到底都干了些什么:
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
这里我们需要再看看getPostMessage这个方法:
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); //新建了一个Message对象 m.callback = r; //将传进来的Runable对象赋给Message对象的callback属性,Message的callback属性本身就是Runnable对象 return m; //返回赋值之后的Message对象 }
对比一下上一篇blog中提到的handler的sendMessage源码:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
到这里我们可以发现post方法和sendMessage方法差不多,都是给消息队列中发送一条消息而已,只不过sendMessage方法中,Message对象是我们自己创建好传进去的,而post方法则是在内部创建一个Message对象,只是将我们传进去的Runnable对象赋值给Message对象的callback属性之后之后再返回而已。下面问题来了:挖掘机技术到底哪家强?开个玩笑。问题应该是这样的,Looper取出了Message对象之后又做了什么?
回顾上一篇blog,其实是通过在loop()方法中,循环到当前的Message对象时,调用msg.target.dispatchMessage(msg)方法,target也就是一个handler对象,其实就是调用handler的dispatchMessage(msg)这个方法来处理取出的消息对象的,那么这里我们再贴一遍这个方法的源代码:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); //当Message对象的callback属性不为空时则调用handleCallback(msg)方法 } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
现在看到这段应该大致明白怎么回事了,上一篇我们没有给callback属性赋值,所以会执行handleMessage方法,但现在我们调用post方法的同时就将一个Runnable对象赋值给了Message的callback属性,所以这里我们自然会走if,下面看看handleCallback(msg)这个方法都做了什么:
private static void handleCallback(Message message) { message.callback.run(); }
到了这里想必大家都已经明白了,直接调用了Runnable的run()方法来运行。有线程基础的话应该很清楚,run()方法和start()方法的区别就在于run()方法不会开启新线程,而是在原有的线程中运行。下面针对开头提出的问题作出解释和更正:
1.上面说执行post方法是将Runnable对象放到消息队列,但消息队列放的都应该是消息对象,即:Message对象,这 里怎么成Runnable对象了?
其实最终放到消息队列的还是Message对象,只是将传进去的Runnable对象赋值给了Message对象的callback属性之后再放到消息队列的。
2.参数的Runnable对象将会被执行,究竟是什么时候执行呢?
看完了最后的一段源码,很明显是Looper取出Message对象之后交给了Handler的handleCallback(msg)方法去处理,也就是在这个方法中通过直接调用run()方法执行了Runnable中的代码。
3.Looper从消息队列中取出放进去的Runnable对象之后,会做什么?
这里需要更正的是放进去的不是Runnable对象,而是Message对象,原因见1。至于做了什么,原因见2。
解释完了之前的问题,也了解了post方法,我们发现这是发送消息的另一种方式,比通过handler的sendMessage要简单一些,并不用继续在主线程中去重写handleMessage(msg)方法,因为Runnable的代码块本身就运行在主线程中。
三、总结
本篇blog主要记录了与handler相关的post方法的使用方法和工作原理,对通过handler发送消息也多了一种选择,关于handler的所有内容到这里基本已经记录完毕,虽然很多地方我个人的理解还不是很到位,但通过阅读源码确实感觉到有很大的收获,剩下的就是时间和努力的问题(鄙人较笨)。后续的blog准备学习记录一些UI方面的知识,比如自定义View、适配器等等,我会继续努力的,争取早日拿下Android!
相关文章推荐
- Android--Handler的post方法详解
- Android中的Handler的post方法详解
- Android中的Handler的post方法详解
- Android中的Handler的post方法详解
- Android中的Handler的post方法详解
- Android中的Handler的post方法详解
- Android中的Handler的post方法详解
- Android的POST方法详解
- 详解Android中使用OkHttp发送HTTP的post请求的方法
- Handler与Android多线程详解(post)
- Handler详解系列(五)——Handler的post()方法详解
- Android中的Handler的post方法
- Android开发之通过Handler的post方法更新UI
- Android笔记(三十四) Android中线程之间的通信(六)Handle中的post()方法详解
- Android:实现定时器 Handler的postDelayed(Runnable, long)方法
- 详解Android中Handler的使用方法
- Android定时器之Handler的postDelyed方法
- 【android】handler.post方法的说明和注意事项
- Android:线程间通讯的其他方法、runOnUiThread(action)、Handler.post(action)、post
- Android中Handler的post方法的作用是什么