Handler 使用方法详解
来源:互联网 发布:李强强 php 编辑:程序博客网 时间:2024/06/06 20:39
Handler是 Android中用来更新UI 的一套消息处理机制。Handler 允许线程间发送Message或Runnable对象进行通信。在Android中UI修改只能通过UI Thread,子线程不能更新UI。如果子线程想更新UI,需要通过 Handler 发送消息给主线程,进而达到更新UI的目的。
欢迎关注微信公众号:程序员Android
公众号ID:ProgramAndroid
获取更多信息
我们不是牛逼的程序员,我们只是程序开发中的垫脚石。
我们不发送红包,我们只是红包的搬运工。
通过本章学习你将掌握以下知识点
- Handler 消息处理机制原理
- Handler 机制处理的4个关键对象
- Handler常用方法
- 子线程更新UI 异常处理
- 主线程给子线程发送消息的方法
- 子线程给主线程发送消息的方法
- 主、子 线程 互发消息方法
- 子线程方法中调用主线程更新UI的方法
继承关系如下:
java.lang.Object ↳ android.os.Handler
1. Handler 消息处理机制原理
当Android 应用程序创建的时候,系统会给每一个进程提供一个Looper ,Looper 是一个死循环,它内部维护一个消息队列,Looper 不停的从消息队列中取Message,取到的消息就发送给handler,最后Handler 根据接收的消息去修改UI等。
2. Handler 机制处理的4个关键对象
1.Message
线程之间传递的消息,可以携带一些简单的数据供子线程与主线程进行交换数据。
2.Message Queue
存放通过Handler 发送的 Message 的消息队列,每一个线程只有一个消息队列。
3.Handler
消息处理者,主要用于发送跟处理消息。
主要功能:
发送消息SendMessage()
处理消息 HandleMessage()
4.Looper
内部包含一个死循环的MessageQueue,用于存储handler 发送的Message,Looper则是不断的从消息队列中取消,如果有消息就取出发送给Handler 处理,没有则阻塞。
总结:
Handler 负责发送Message到Message Queue,Looper负责从Message Queue 遍历Message ,然后直接把遍历的消息回传给Handler 自己,通过Handler 自身的handleMessage处理更新UI等操作。
3. Handler常用方法
1.Runnable对象
- post(Runnable)
使用方法举例:
private Handler mRunnableHandler = new Handler(); public void RunnableHandlderMethod() { new Thread() { @Override public void run() { try { Thread.sleep(1000); mRunnableHandler.post(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_runnable)).setText("Runnable"); } }); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }
- postAtTime(Runnable, long)
- postDelayed(Runnable, long)
- Message 对象
- sendEmptyMessage(int)
使用方法举例:
private int mCount = 0; private Handler mMessageHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ((Button) findViewById(R.id.btn_thread)).setText("" + mCount); } }; class MessageHandlerThreadMethod extends Thread { String mString; public MessageHandlerThreadMethod(String str) { mString = str; } @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (Exception e) { } mCount++; mMessageHandler.sendEmptyMessage(0); } } } //1.Message 对象 new MessageHandlerThreadMethod("子线程不能更新UI").start();
- sendMessage(Message),
使用方法举例:
- sendMessageAtTime(Message, long),
- sendMessageDelayed(Message, long)
3.接收、处理Message
- handleMessage(Message)
使用方法举例:
private Handler mMessageHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ((Button) findViewById(R.id.btn_thread)).setText("" + mCount); } };
4. 子线程更新UI 异常处理
子线程不能更新UI,如果在子线程中更新UI,会出现CalledFromWrongThreadException 异常。
- CalledFromWrongThreadException
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
解决方法:
子线程通过Handler 发送消息给主线程,让主线程处理消息,进而更新UI。
5. 主线程给子线程发送消息的方法
此例子中子线程通过Looper不断遍历主线程发送的消息,Looper 使用方法如下:
- 准备Looper 轮询器
Looper.prepare();
- 准备Looper 轮询器
- Handler 处理遍历消息
Handler mHandler = new Handler()
- Handler 处理遍历消息
- 遍历消息队列
Looper.loop();
- 遍历消息队列
Looper 使用方法如下:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
主线程发送消息的使用例子如下:
public void BtnMainMessageMethod(View view) { Message msg = new Message(); msg.obj = "主线程:这是我携带的信息"; if (mMainHandler != null) { mMainHandler.sendMessage(msg); } else { Toast.makeText(getApplicationContext(), "开启子线程轮询消息,请再次点击发送消息", Toast.LENGTH_SHORT).show(); //开启轮询线程,不断等待接收主线成消息 new ChildLooperThread().start(); } } private Handler mMainHandler; String mMainMessage; // 自定义 Loop 线程 ---> 不停的处理主线程发的消息 class ChildLooperThread extends Thread { @Override public void run() { // 1.准备成为loop线程 Looper.prepare(); // 2.处理消息 mMainHandler = new Handler() { // 处理消息 public void handleMessage(Message msg) { super.handleMessage(msg); mMainMessage = (String) msg.obj; Log.i("TAG", "子线程:从主线程中接受的消息为:\n" + mMainMessage); // 使用 runOnUiThread 在主线程中更新UI runOnUiThread(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_main_message)).setText(mMainMessage); } }); } }; // 3.Loop循环方法 Looper.loop(); } }
6. 子线程给主线程发送消息的方法
子线程发送消息给主线程方法
public void BtnChildMessageMethod(View view) { new Thread() { public void run() { while (mCount < 100) { mCount++; try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } /** * 利用handler 对象发送消息 * Message msg=Message.obtain(); * Message msg=new Message(); 获取一个消息对象message * */ Message msg = Message.obtain(); // 消息标记 msg.what = 1; // 传递整型值msg.obj="传递object数据" msg.arg1 = mCount; Log.i("TAG", "count 值=" + mCount); if (mhandler != null) { mhandler.sendMessage(msg); } } } ; }.start(); } //定义一个handler 主线程 接收子线程发来的信息 private Handler mhandler = new Handler() { // 處理消息的方法 public void handleMessage(android.os.Message msg) { switch (msg.what) { case 1: int value = msg.arg1; Log.i("TAG", "value值=" + value); ((Button) findViewById(R.id.btn_child_message)).setText("当前值=" + value); break; default: break; } } };
7. 主、子 线程 互发消息方法
主要实现主、子线程每隔1s中通信一次
- 实现打印Log如下:
- 实现方法如下:
public void BtnChildMessageMethod(View view) { new Thread() { public void run() { while (mCount < 100) { mCount++; try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } /** * 利用handler 对象发送消息 * Message msg=Message.obtain(); * Message msg=new Message(); 获取一个消息对象message * */ Message msg = Message.obtain(); // 消息标记 msg.what = 1; // 传递整型值msg.obj="传递object数据" msg.arg1 = mCount; Log.i("TAG", "count 值=" + mCount); if (mhandler != null) { mhandler.sendMessage(msg); } } } ; }.start(); } //定义一个handler 主线程 接收子线程发来的信息 private Handler mhandler = new Handler() { // 處理消息的方法 public void handleMessage(android.os.Message msg) { switch (msg.what) { case 1: int value = msg.arg1; Log.i("TAG", "value值=" + value); ((Button) findViewById(R.id.btn_child_message)).setText("当前值=" + value); break; default: break; } } }; private Handler mChildHandler; //创建主线程 private Handler mainhandler = new Handler() { @Override public void handleMessage(Message msg) { Log.i("TAG", "子线程对我说:" + msg.obj);// 主线成携带的消息内容 Message message = new Message(); message.obj = Thread.currentThread() + "我是主线程:小子你得听我的。";// 向子线程发送消息 mChildHandler.sendMessageDelayed(message, 1000); } }; public void BtnMainChildMessageMethod(View view) {// 创建 名称为currentThread 子线程 HandlerThread mChildThread = new HandlerThread("ChildThread"); mChildThread.start(); mChildHandler = new Handler(mChildThread.getLooper()) { @Override public void handleMessage(Message msg) { Log.i("TAG", "主线程对我说:" + msg.obj); // 子线程携带的消息 Message message = new Message(); message.obj = Thread.currentThread() + "我是子线程,小样,让我听你的没门";// 向主线程发送消息 mainhandler.sendMessageDelayed(message, 1000); } }; // 主线成发送空消息,开启通信 mainhandler.sendEmptyMessage(1); }
8.子线程方法中调用主线程更新UI的方法
- Activity 中 可以使用runOnUiThread(Runnable)
// 使用 runOnUiThread 在主线程中更新UI runOnUiThread(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_main_message)).setText(mMainMessage); } });
- Handler.post(Runnable)
mRunnableHandler.post(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_runnable)).setText("Runnable"); } });
- View.post()
((Button) findViewById(R.id.btn_runnable)).post(new Runnable() { @Override public void run() { ((Button) findViewById(R.id.btn_runnable)).setText("Runnable"); } });
- Handler.sendMessage(Message)
至此,线程间通信已结束,
欢迎关注微信公众号:程序员Android
公众号ID:ProgramAndroid
获取更多信息
我们不是牛逼的程序员,我们只是程序开发中的垫脚石。
我们不发送红包,我们只是红包的搬运工。
点击阅读原文,获取更多福利
- Handler 使用方法详解
- 详解Android中Handler的使用方法
- Handler使用方法
- Handler 使用方法
- Handler使用方法
- Handler使用方法
- Handler使用方法
- 详解Asytask和Handler的区别和使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- Handler的基本使用方法
- HandlerThread,Handler,Thread使用方法
- 学习-Handler的使用方法
- HandlerThread,Handler,Thread使用方法
- HandlerThread,Handler,Thread使用方法
- Android Handler的使用方法
- HandlerThread,Handler,Thread使用方法
- 安卓 Handler使用方法
- Java面试(解答题二)
- H5 3D动画实现
- EEPROM和flash的区别
- JS表单验证
- PageHelper分页插件源码及原理剖析
- Handler 使用方法详解
- request和response
- 第五周项目三
- leetcode 383. Ransom Note HashMap查询加速
- <!-- 自动推送工具代码-->
- 实验二 线性表-顺序表(JavaScript实现)
- Modbus 通讯协议数据帧之间的时间停顿间隔 “3.5字符”定义
- Linux——用户
- 堆和栈的区别(转)