Android学习总结(十七) ———— Handler 的使用
一、基本概念
handler通俗一点讲就是用来在各个线程之间发送数据的处理对象。在任何线程中,只要获得了另一个线程的handler,则可以通过 handler.sendMessage(message)方法向那个线程发送数据。基于这个机制,我们在处理多线程的时候可以新建一个thread,这个thread拥有UI线程中的一个handler。当thread处理完一些耗时的操作后通过传递过来的handler向UI线程发送数据,由UI线程去更新界面。
主线程:运行所有UI组件,它通过一个消息队列来完成此任务。设备会将用户的每项操作转换为消息,并将它们放入正在运行的消息队列中。主线程位于一个循环中,并处理每条消息。如果任何一个消息用时超过5秒,Android将抛出ANR。所以一个任务用时超过5秒,应该在一个独立线程中完成它,或者延迟处理它,当主线程空闲下来再返回来处理它。
二、Handler类的引入
(图片来源:http://www.runoob.com/w3cnote/android-tutorial-handler-message.html)

三、Handler的执行流程图
(图片来源:http://www.runoob.com/w3cnote/android-tutorial-handler-message.html)

流程图解析: 相关名词
- UI线程:就是我们的主线程,系统在创建UI线程的时候会初始化一个Looper对象,同时也会创建一个与其关联的MessageQueue;
- Handler:作用就是发送与处理信息,如果希望Handler正常工作,在当前线程中要有一个Looper对象
- Message:Handler接收与处理的消息对象
- MessageQueue:消息队列,先进先出管理Message,在初始化Looper对象时会创建一个与之关联的MessageQueue;
- Looper:每个线程只能够有一个Looper,管理MessageQueue,不断地从中取出Message分发给对应的Handler处理!
四、示例代码
4.1Handler写在主线程中
在主线程中,因为系统已经初始化了一个Looper对象,所以我们直接创建Handler对象,就可以进行信息的发送与处理了!布局代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"> <ImageView
android:id="@+id/imgChange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"/> </RelativeLayout>
MainActivity.java代码如下所示:
package com.nyl.handlertest; import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView; import java.util.Timer;
import java.util.TimerTask; public class MainActivity extends Activity { private ImageView imgChange; //定义切换的图片的数组id
int imgids[] = new int[]{
R.mipmap.ic_launcher,R.mipmap.h,R.mipmap.h1,
R.mipmap.h2,R.mipmap.h3,R.mipmap.h4,
R.mipmap.h5,R.mipmap.h6}; int imgStart = 0;
final Handler handler = new Handler(){
/**
* 重写 handleMessage方法,根据msg中what的值判断是否执行后续操作
* @param msg
*/
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123){
imgChange.setImageResource(imgids[imgStart++ % 8]);
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); imgChange = (ImageView) findViewById(R.id.imgChange);
//使用定时器,每个200毫秒让handler发送一个空信息
new Timer().schedule(new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(0x123);
}
},0,200);
}
}
当我们运行程序的时候,会每2秒跳到下一个图片去,(由于是动态的没法去给大家演示效果)还是自己去动手操作吧!
4.2 Handler写在子线程中
如果是Handler写在了子线程中的话,我们就需要自己创建一个Looper对象了!创建的流程如下:
- 直接调用Looper.prepare()方法即可为当前线程创建Looper对象,而它的构造器会创建配套的MessageQueue;
- 创建Handler对象,重写handleMessage( )方法就可以处理来自于其他线程的信息了!
- 调用Looper.loop()方法启动Looper
输入一个数,计算后通过Toast输出在这个范围内的所有质数,布局如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <EditText
android:id="@+id/etNum"
android:inputType="number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入上限"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="cal"
android:text="计算"/>
</LinearLayout>
关键代码,如下所示:
package com.nyl.handlerdemo; import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast; import java.util.ArrayList;
import java.util.List; public class MainActivity extends Activity { private static String UPPER_NUM = "upper";
private EditText etNum;
CalThread calThread; //定义一个线程类
class CalThread extends Thread{
public Handler handler; public void run(){
Looper.prepare();
handler = new Handler(){
//定义处理消息的方法
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123){
int upper = msg.getData().getInt(UPPER_NUM);
List<Integer> nums = new ArrayList<>();
//计算从2开始,到upper的所有质数
outer:
for (int i = 2; i <= upper; i++){
//用i处于从2开始,到i的平方根的所有数
for (int j = 2; j<= Math.sqrt(i); j ++){
// 如果可以整除,表明这个数不是质数
if(i != 2 && i % j == 0) {
continue outer;
}
}
nums.add(i);
}
// 使用Toast显示统计出来的所有质数
Toast.makeText(MainActivity.this , nums.toString(), Toast.LENGTH_LONG).show();
}
}
};
Looper.loop();
}
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etNum = (EditText) findViewById(R.id.etNum);
calThread = new CalThread();
//启动新线程
calThread.start();
}
//为按钮的点击事件提供事件处理函数
public void cal(View source){
//创建消息
Message message = new Message();
message.what = 0x123;
Bundle bundle = new Bundle();
bundle.putInt(UPPER_NUM,Integer.parseInt(etNum.getText().toString()));
message.setData(bundle);
//向新线程中的Handler发送消息
calThread.handler.sendMessage(message);
} }
当输入数字,点击计算按钮时,运行效果如下所示:

OK,Handler 的使用我们就暂时学到这里,有什么不足的地方欢迎朋友们提出宝贵建议!
Android学习总结(十七) ———— Handler 的使用的更多相关文章
- Android学习笔记(38):Handler消息传递处理机制
先说为什么须要Handler: Android的主线程又叫UI线程,用于处理与UI相关的时间.Android仅仅同意在主线程中改动UI组件,当我们在其它线程中须要改动UI界面时.就须要发送消息到主线程 ...
- android 学习随笔十七(服务 )
1.Service 四大组件之一 运行于后台,没有前台界面的组件,用于运行需要在后台运行的代码 可以理解为没有前台的Activity 定义方式:创建java类继承Service,清单文件中注册该类 p ...
- Android学习(十七)自定义View控件 TopBar
一.创建自定义TopBar头部菜单条 实现步骤: 1.在values中添加attrs.xml文件,设置自定义属性. 2.添加Topbar类,继承RelativeLayout,实现具体功能. 3.添加到 ...
- 【转】 Pro Android学习笔记(九十):了解Handler(4):Worker线程
目录(?)[-] worker线程小例子 小例子代码worker线程通过handler实现与主线程的通信 小例子代码继承Handler代码 小例子代码子线程的Runnable 文章转载只能用于非商业性 ...
- 【转】 Pro Android学习笔记(八九):了解Handler(3):延迟执行小例子
目录(?)[-] 小例子 Handler的处理 Activity的代码片段 后台线程和UI的互动 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://b ...
- android学习系列:jercy——AI3 的博客
[android学习之十七]——特色功能2:桌面组件(快捷方式,实时文件夹) 二.桌面组件 1.快捷方式 Android手机上得快捷方式的意思可以以我们实际PC机器上程序的快捷方式来理解.而andro ...
- 六、Android学习第五天——Handler的使用(转)
(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 六.Android学习第五天——Handler的使用 注意:有很多功能是不 ...
- 【转】 Pro Android学习笔记(八八):了解Handler(2):什么是Handler
文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 之前我们有一篇很好的博文<Andro ...
- IOS学习之十七:Grand Central Dispatch(GCD)编程基础
IOS学习之十七:Grand Central Dispatch(GCD)编程基础 有过编程经验的人,基本都会接触到多线程这块. 在java中以及Android开发中,大量的后台运行,异步消息队列, ...
- 《Android学习指南》目录
源:<Android学习指南>目录 Android学习指南的内容分类: 分类 描述 0.学习Android必备的Java基础知识 没有Java基础的朋友,请不要先看Android的课程,这 ...
随机推荐
- 【HBase】HBase笔记:HBase的Region机制
HBase 的机制里包含了许多优秀的算法,如 Region 定位.Region 分配.Region Server的上线和下线.Master 的上线和下线.在谈到这些之前,先把 HBase 的基本架构里 ...
- Qt生成CSV 文件
1.CSV 文件 不支持 EXCEL中 的多个工作表的模式. 一个 CVS 文件只能转换成 EXCEL 一个工作表. 2.逗号分隔值(Comma-Separated Values,CSV,有时也称为字 ...
- 51nod 1021【区间DP】
思路: dp[ i ] [ j ]代表取[ i ,j ]区间石子的最小值,然后dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); # ...
- IT行业技术及程序员相关网站荟萃
最近我花了一些时间收集了一些与自己工作相关的常用的网址,由于时间关系,暂时只是收集了这么多,以后有时间再随时添加. 1.程序员网址导航pg265 http://www.pg265.com/TNT程序网 ...
- C#箴言:定义常量的两种方法
在C#中定义常量的方式有两种, 一种叫做静态常量(Compile-time constant),另一种叫做动态常量(Runtime constant). 前者用"const"来定义 ...
- __str__,__repr__
目录 __str__ __repr__ __str__ 打印时触发 class Foo: pass obj = Foo() print(obj) <__main__.Foo object at ...
- 跳转到另一个APP
看看这个代码: http://code4app.com/codesample/4fcc512d6803fae60b000002 inApp跳转,不过需要Nimbus类库. 要跳转到另一个APP,需要另 ...
- 多线程 NSThread 了解
用NSThread创建子线程的3种方法 // DYFViewController.m // 623-02-pthread // // Created by dyf on 14-6-23. / ...
- Luogu P1092 虫食算【搜索/剪枝】 By cellur925
题目传送门 这道题是一道经久不衰的搜索题目,但是开始做的时候我没什么思路==.初始值-1 输出格式 \(naive\)想法 从右往左依次尝试填充数字,把算式当做一个3行\(n\)列的网格.(什么?你问 ...
- 【微服务】Dubbo初体验
一.前言 之前微服务这块只用过SpringCloud搭建,但是最近面试会被问到dubbo框架,虽然之前也学了但是都忘了,故写此博客加深印象. 二.原理简介 Dubbo是一个分布式服务框架,以及阿里巴巴 ...