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的课程,这 ...
随机推荐
- 【旧文章搬运】Win7可变对象头结构之InfoMask解析
原文发表于百度空间,2010-08-11========================================================================== 对Wind ...
- AspNetPager样式以及属性帮助文档
帮助文档地址:http://www.webdiyer.com/AspNetPagerDocs/index.html 应用样式:http://www.webdiyer.com/AspNetPagerDe ...
- 1.1-1.4 hadoop调度框架和oozie概述
一.hadoop调度框架 Linux Crontab Azkaban https://azkaban.github.io/ Oozie http://oozie.apache.org/ Zeus(阿里 ...
- 13.详解oauth2授权码流程
13.详解oauth2授权码流程 把登陆系统单独独立出来,可以给自己写的微服务用,也可以给第三方的系统调用我们的服务 显式的和隐式的,两种方式,
- bootstrap的tab中,echarts 图表宽度设为100%之后,会出现图表宽带变为100px的情况。只有第一个正常
1.原因 echarts官方解释是 Tip: 有时候图表会放在多个标签页里,那些初始隐藏的标签在初始化图表的时候因为获取不到容器的实际高宽,可能会绘制失败,因此在切换到该标签页时需要手动调用resiz ...
- 豆瓣api获取图片403
1.问题描述 豆瓣的图片资源在网页中不能正常显示,403禁止访问,把地址放到浏览器中就可以正常访问了? 原因是豆瓣现在有防盗链 2.解决问题 在页面中加上 <meta name="re ...
- 解决overflow: auto在Ios中滑动不流畅
[bug]—— H5页面在 ios 端滑动不流畅的问题 IOS系统的惯性滑动效果非常6,但是当我们对div加overflow-y:auto;后是不会出这个效果的,滑动的时候会感觉很生涩.怎么办? ...
- hyperledger fabric 1.0.5 分布式部署 (一)
环境是个人虚拟机ubuntu 16.04 64 位版本 前期用户需要先安装好:gcc.g++.git 软件 安装 golang 首先给环境安装一个 go 语言环境,版本最好在1.8 以上 golang ...
- native-echarts 在安卓上无法显示出来
1.native-echarts 的配置是百度echarts 2.模拟器上试了很多次都显示不出来(具体不清楚,我的是这样) 3.真机测试可以显示图表,以下是配置: a.将node_modules\na ...
- B. Mancala (Codeforces Round #478 (Div. 2))
#include <bits/stdc++.h> using namespace std; ; typedef long long ll; ll a[maxn]; ll b[maxn]; ...