安卓handler机制和RunOnUi方法都能修改主线程,两者的区别
来源:互联网 发布:基金买卖模拟软件 编辑:程序博客网 时间:2024/04/29 12:47
今天一个哥们说他去公司面试,碰到这个问题:安卓handler机制和RunOnUi方法都能修改主线程,两者的区别。
拿给我看,也是不甚了解,所以这里我们先看下app的运行机制:
从图中我们可以看到,当我们从外部调用组件的时候,Service 和 ContentProvider 是从线程池那里获取线程,而Activity 和BroadcastReceiver是直接在主线程运行。
为什么要使用Handlers?
因为,我们当我们的主线程队列,如果处理一个消息超过5秒,android 就会抛出一个 ANP(无响应)的消息,所以,我们需要把一些要处理比较长的消息,放在一个单独线程里面处理,把处理以后的结果,返回给主线程运行,就需要用的Handler来进行线程建的通信,关系如下图;
下面是Handler,Message,Message Queue 之间的关系图
这个图有4个地方关系到handlers
1, 主线程(Main thread)
2, 主线程队列(Main thread queue)
3,Hanlder
4,Message
上面的四个地方,主线程,和主线程的队列我们无需处理,所以,我们主要是处理Handler 和 Message 之间的关系.
我们每发出一个Message,Message就会落在主线程的队列当中,然后,Handler就可以调用Message绑定的数据,对主线程的组件进行操作.
好了,看完了相关信息handler的相关信息,我们再来看下,我们这次运行代码的时候,是怎么利用handler更新主界面UI的流程:事件响应→开启线程→new Message();→new Bundle();→bundle.putString("event", "Handler更改UI");→msg.setData(bundle);→handler.sendMessage(msg);→new handler(msg.getdata→getString→更改UI)
代码如下:
handler事件响应:
findViewById(R.id.button1).setOnClickListener(new OnClickListener() {<span style="white-space:pre"></span>@Override<span style="white-space:pre"></span>public void onClick(View v) {<span style="white-space:pre"></span>Log.e("事件ing。。。开始", "进入点击事件");<span style="white-space:pre"></span>UIThread thread = new UIThread();<span style="white-space:pre"></span>thread.start();<span style="white-space:pre"></span>UIhandler = new UIHandler();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>});
/** * 继承Handler的子类,必须先实现handlerMessage这个方法 * * @author 阿程 * */private class UIHandler extends Handler {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);Log.e("事件ing。。。", "handler收到传递过来的消息");Bundle bundle = msg.getData();Log.e("事件ing。。。", "接受传递过来的msg里面的包裹内容");String str = bundle.getString("event");Log.e("事件ing。。。", "打开包裹。接受传递过来的东西");UITxt.setText(str);Log.e("事件ing。。。结束", "主界面UI做出相应的变化");}}/** * Massage发送信息调用handler实例 * * @author Administrator * */private class UIThread extends Thread {@Overridepublic void run() {try {Thread.sleep(3000);Log.e("事件ing。。。", "模拟耗时操作3秒和runOnUiThread方法做对比");} catch (InterruptedException e) {e.printStackTrace();}Log.e("事件ing。。。", "捆绑信息到msg,并发送msg");Message msg = new Message();Log.e("事件ing。。。", "先创建出来msg");Bundle bundle = new Bundle();Log.e("事件ing。。。", "创建包裹");bundle.putString("event", "Handler更改UI");Log.e("事件ing。。。", "将信息装入包裹");msg.setData(bundle);Log.e("事件ing。。。", "将包裹装入msg");MainActivity.this.UIhandler.sendMessage(msg);Log.e("事件ing。。。", "主界面UI发送msg");}}咱贴上代码运行耗时截图:
(为了相对直观,咱都模拟了耗时操作)
RunOnUi事件响应:
findViewById(R.id.button2).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Log.e("事件go。。。开始", "进入点击事件");new RunOnUiThread().start();}});
RunOnUi线程:
/** * 创建实现RunOnUi更改主界面的线程实例 * * @author Administrator * */private class RunOnUiThread extends Thread {@Overridepublic void run() {// 模拟耗时的操作。try {Log.e("事件go。。。", "模拟耗时操作3秒和runOnUiThread方法做对比");Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}Log.e("事件go。。。", "runOnUiThread开始");// 更新主线程UIMainActivity.this.runOnUiThread(new Runnable() {@Overridepublic void run() {UITxt.setText("runOnUi更改UI");Log.e("事件go。。。结束", "runOnUiThread结束");}});}}代码运行耗时截图:
相信这上面的一番对比 大家都明白了不少。下面贴出总得源码:
package com.example.handler_runonuithread;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.widget.EditText;import android.widget.TextView;public class MainActivity extends Activity {EditText UITxt;UIHandler UIhandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);UITxt = (EditText) findViewById(R.id.editText1);findViewById(R.id.button1).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Log.e("事件ing。。。开始", "进入点击事件");UIThread thread = new UIThread();thread.start();UIhandler = new UIHandler();}});findViewById(R.id.button2).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Log.e("事件go。。。开始", "进入点击事件");new RunOnUiThread().start();}});}/** * 继承Handler的子类,必须先实现handlerMessage这个方法 * * @author 阿程 * */private class UIHandler extends Handler {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);Log.e("事件ing。。。", "handler收到传递过来的消息");Bundle bundle = msg.getData();Log.e("事件ing。。。", "接受传递过来的msg里面的包裹内容");String str = bundle.getString("event");Log.e("事件ing。。。", "打开包裹。接受传递过来的东西");UITxt.setText(str);Log.e("事件ing。。。结束", "主界面UI做出相应的变化");}}/** * Massage发送信息调用handler实例 * * @author Administrator * */private class UIThread extends Thread {@Overridepublic void run() {try {Thread.sleep(3000);Log.e("事件ing。。。", "模拟耗时操作3秒和runOnUiThread方法做对比");} catch (InterruptedException e) {e.printStackTrace();}Log.e("事件ing。。。", "捆绑信息到msg,并发送msg");Message msg = new Message();Log.e("事件ing。。。", "先创建出来msg");Bundle bundle = new Bundle();Log.e("事件ing。。。", "创建包裹");bundle.putString("event", "Handler更改UI");Log.e("事件ing。。。", "将信息装入包裹");msg.setData(bundle);Log.e("事件ing。。。", "将包裹装入msg");MainActivity.this.UIhandler.sendMessage(msg);Log.e("事件ing。。。", "主界面UI发送msg");}}/** * 创建实现RunOnUi更改主界面的线程实例 * * @author Administrator * */private class RunOnUiThread extends Thread {@Overridepublic void run() {// 模拟耗时的操作。try {Log.e("事件go。。。", "模拟耗时操作3秒和runOnUiThread方法做对比");Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}Log.e("事件go。。。", "runOnUiThread开始");// 更新主线程UIMainActivity.this.runOnUiThread(new Runnable() {@Overridepublic void run() {UITxt.setText("runOnUi更改UI");Log.e("事件go。。。结束", "runOnUiThread结束");}});}}}
至于布局文件中,只有三个控件,两个按钮一个文本框,这里不再贴上代码。
但是,你以为这样就完了嘛?
NO,not only this!
首先,我们看上面我们的handler控制界面UI的流程:
事件响应→开启线程→new Message();→new Bundle();→bundle.putString("event", "Handler更改UI");→msg.setData(bundle);→handler.sendMessage(msg);→new handler(msg.getdata→getString→更改UI)
具体就是这样,那RunOnUi的流程呢?
爬源码所得如下:
事件响应→开启线程→runOnUiThread→判断是否当前线程为主UI线程(是就立刻执行,不是就通过handler.post()发送到动作序列中,等到是主UI线程再立刻执行)
官方源码介绍如下:
<strong><span style="color:#ff0000;">/** * 在UI线程里面执行指定的动作. 如果当前线程是UI线程,则立刻执行该动作, * 如果当前线程不是UI线程,则将该动作发送到动作序列中,等UI线程为当前线程时再执行。 * @action 传递的参数为action * @param action the action to run on the UI thread */ public final void runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); } }</span></strong>
相信看到这里哥们都明白啥意思了,弄哎暗着了,我也滚去困瞌睡了。
- 安卓handler机制和RunOnUi方法都能修改主线程,两者的区别
- 安卓之Handler子线程和主线程的交互
- androd中主线程和非主线程的通信机制(Handler/Looper/Message)
- 主线程、Handler机制原理
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- 『ANDROID』Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- 安卓基础:Handler, Looper,消息队列,线程及主线程之间的关系
- 安卓Handler机制
- Course Schedule
- mybatis注解方式懒加载失效分析
- Ubuntu 14.04常用软件及其安装
- linux下ftp的server/client的部署及使用
- PHP中单引号和双引号的区别
- 安卓handler机制和RunOnUi方法都能修改主线程,两者的区别
- 两层Fragment嵌套,外层Fragment切换时内层Fragment不显示内容
- WEB-注意事项
- hdu 1231, dp ,maximum consecutive sum of integers, find the boundaries, possibly all negative, C++
- org.apache.ibatis.binding.BindingException【原因汇总】
- 微服务架构成功之路
- POJ-1046
- 普通美国人的词汇量
- win7旗舰版下怎么配置ODBC数据源