极力推荐文章:欢迎收藏

Android 干货分享

阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

  1. Handler 消息处理机制原理
  2. Handler 机制处理的4个关键对象
  3. Handler常用方法
  4. 子线程更新UI 异常处理
  5. 主线程给子线程发送消息的方法
  6. 子线程给主线程发送消息的方法
  7. 主、子 线程 互发消息方法
  8. 子线程方法中调用主线程更新UI的方法

HandlerAndroid中用来更新UI 的一套消息处理机制。Handler 允许线程间发送MessageRunnable对象进行通信。在Android中UI修改只能通过UI Thread,子线程不能更新UI。如果子线程想更新UI,需要通过 Handler 发送消息给主线程,进而达到更新UI的目的。

Handler 简介

继承关系如下:

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 发送的MessageLooper则是不断的从消息队列中取消,如果有消息就取出发送给Handler 处理,没有则阻塞。

总结:

Handler 负责发送MessageMessage QueueLooper负责从Message Queue 遍历Message ,然后直接把遍历的消息回传给Handler 自己,通过Handler 自身的handleMessage处理更新UI等操作。

3. Handler常用方法

1.Runnable对象

  • post(Runnable)

使用方法举例:

	public void BtnRunnableMethod(View view) {
// 1.Runnable 对象
RunnableHandlderMethod();
} /**
* Runnable 对象更新 UI
* **/
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)

2. Message 对象

  • sendEmptyMessage(int)

使用方法举例:

	public void BtnMessageThreadMethod(View view) {
// 2.Message 对象
new MessageHandlerThreadMethod("子线程不能更新UI").start();
}
/**
* Message 对象举例
* ***/
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);
} }
}
  • sendMessage(Message)

使用方法举例:

public void BtnMessageObjMethod(View view) {
HandlerMessageObjMethods();
} /***
* handler sendmessage 处理方法
* **/
private Handler mHandlerMessageObj = new Handler() { @Override
public void handleMessage(Message msg) { ((Button) findViewById(R.id.btn_message)).setText("arg1:"
+ msg.arg1 + "\n" + msg.obj);
}
}; private void HandlerMessageObjMethods() {
new Thread() {
@Override
public void run() { try {
Thread.sleep(1000);
// Message message = new Message();
Message message = mHandlerMessageObj.obtainMessage(); message.arg1 = 100; Person person = new Person();
person.name = "Lucy";
person.age = 12; message.obj = person;
mHandlerMessageObj.sendMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
} class Person { public int age;
public String name; public String toString() {
return "Name=" + name + "\n Age=" + age;
} }
  • 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

解决方法:

子线程通过Handler 发送消息给主线程,让主线程处理消息,进而更新UI

5. 主线程给子线程发送消息的方法

此例子中子线程通过Looper不断遍历主线程发送的消息,Looper 使用方法如下:

    1. 准备Looper 轮询器

Looper.prepare();

    1. Handler 处理遍历消息

Handler mHandler = new Handler()

    1. 遍历消息队列

Looper.loop();

Looper 使用方法如下:

	// 自定义 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);
... ...
}
});
}
};
// 3.Loop循环方法
Looper.loop();
} }

主线程发送消息给子线程 的使用例子如下:

  1. 启动 子线程,并再启动后发送消息

public void BtnMainMessageMethod(View view) {
// 点击主线程 按钮,启动子线程,并在子线程启动后发送消息
Message msg = new Message();
msg.obj = "主线程:这是我携带的信息";
if (mMainHandler != null) {
// 2.主线程发送消息
mMainHandler.sendMessage(msg);
} else {
Toast.makeText(getApplicationContext(), "开启子线程轮询消息,请再次点击发送消息",
Toast.LENGTH_SHORT).show();
// 1.开启轮询线程,不断等待接收主线成消息
new ChildLooperThread().start();
}
}
  1. 子线程启动,不停的变量主线程发送的消息
	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. 子线程给主线程发送消息的方法

1.子线程发送消息给主线程方法


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();
}

2.主线程接收并处理消息的方法

// 定义一个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如下:

  • 实现方法如下:
  1. 启动子线程并发送给主线程消息
	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);
}

2.主线程接收并处理子线程发送的消息

	// 创建主线程
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);
}
};

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() {
// TODO Auto-generated method stub
((Button) findViewById(R.id.btn_runnable)).setText("View.post()方法使用");
}
});

Handler.sendMessage(Message)

	public void BtnMainMessageMethod(View view) {
// 点击主线程 按钮,启动子线程,并在子线程启动后发送消息
Message msg = new Message();
msg.obj = "主线程:这是我携带的信息";
if (mMainHandler != null) {
// 2.主线程发送消息
mMainHandler.sendMessage(msg);
}
}

9.移除Handler 发送的消息方法

1.移除 handler 发送的所有消息

private Handler mChildHandler;
mChildHandler.removeCallbacksAndMessages(null);

2.移除 指定消息

private Handler mainhandler;
mainhandler.removeMessages(what);

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

Handler 使用详解的更多相关文章

  1. android Handler机制详解

      简单运行图:    名词解析: Message(消息):定义了一个包含描述以及随意的数据对象可以被发送到Hanlder的消息,获得消息的最好方法是Message.obtain或者Handler.o ...

  2. Handler知识点详解

    Handler是在多线程之间使用的,用于线程之间进行通信. 要想知道为什么需要Handler就首先说明android的主线程和工作线程. 主线程又称为UI线程.正是因为在android中,所有与UI有 ...

  3. 【Android】Android实现Handler异步详解

    方式不止一种,这里使用的是Timer类,创建一个定时器.我们经常需要获得移动设备端口的显示屏信息,但是onCreate()方法执行的时候,OnShow()方法不一定执行了,也就是说,在执行Oncrea ...

  4. Android学习总结(3)——Handler深入详解

    什么是Handler Handler是Android消息机制的上层接口,它为我们封装了许多底层的细节,让我们能够很方便的使用底层的消息机制.Handler的最常见应用场景之一便是通过Handler在子 ...

  5. android Handler机制之ThreadLocal详解

    概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Messa ...

  6. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  7. Message,MessageQueue,Looper,Handler详解+实例

    Message,MessageQueue,Looper,Handler详解+实例 原文地址 Android的Handler使用(这篇简单介绍Handler的使用) 一.几个关键概念 1.Message ...

  8. Message,MessageQueue,Looper,Handler详解

    Message,MessageQueue,Looper,Handler详解   一.几个关键概念 1.MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方.每一个线程最 ...

  9. Handler Looper 原理 详解

    演示代码 public class MainActivity extends ListActivity {     private TextView tv_info;     private CalT ...

随机推荐

  1. Redis 学习笔记(篇四):整数集合和压缩列表

    整数集合 Redis 中当一个集合(set)中只包含整数,并且元素不多时,底层使用整数集合实现,否则使用字典实现. 那么: 为什么会出现整数集合呢?都使用字典存储不行吗? 整数集合在 Redis 中的 ...

  2. Python笔记【5】_字符串&列表&元组&字典之间转换学习

    #!/usr/bin/env/python #-*-coding:utf-8-*- #Author:LingChongShi #查看源码Ctrl+左键 #数据类型之间的转换 Str='www.baid ...

  3. Js笛卡尔乘积

    self.getDescartesSku = function (selSaleProp, i, nowLst, allALst) {         if (selSaleProp.length = ...

  4. redis源码笔记-内存管理zmalloc.c

    redis的内存分配主要就是对malloc和free进行了一层简单的封装.具体的实现在zmalloc.h和zmalloc.c中.本文将对redis的内存管理相关几个比较重要的函数做逐一的介绍 参考: ...

  5. Windows下通过VNC远程访问Linux服务器,并实现可视化

    前言 最近因部门需要,老大想让我在公司Linux服务器上弄个Oracle,以用作部门测试环境的数据库服务器,经过一番折腾后,成功完成了任务.因公司Linux服务器是无图形界面的,本人接触Linux不多 ...

  6. 基于缓存或zookeeper的分布式锁实现

    缓存锁  我们常常将缓存作为分布式锁的解决方案,但是却不能单纯的判断某个 key 是否存在 来作为锁的获得依据,因为无论是 exists 和 get 命名都不是线程安全的,都无法保证只有一个线程可以获 ...

  7. 关于爬虫平台的架构实现和框架的选型(二)--scrapy的内部实现以及实时爬虫的实现

    我们接着关于爬虫平台的架构实现和框架的选型(一)继续来讲爬虫框架的架构实现和狂阶的选型. 前面介绍了scrapy的基本操作,下面介绍下scrapy爬虫的内部实现架构如下图 1.Spiders(爬虫): ...

  8. Docker学习第二天

    CentOS 系列安装 Docker Docker 支持 CentOS6 及以后的版本. CentOS6 对于 CentOS6,可以使用 EPEL 库安装 Docker,命令如下 [root@MSJT ...

  9. Junit初级应用实例

    Request: public interface Request { String getName(); } Response: public interface Response { String ...

  10. 【题解】旅行-C++

    Description 某趟列车的最大载客容量为V人,沿途共有n个停靠站,其中始发站为第1站,终点站为第n站.在第1站至第n-1站之 间,共有m个团队申请购票搭乘,若规定:(1)对于某个团队的购票申请 ...