一、基本概念

   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对象了!创建的流程如下:

  1. 直接调用Looper.prepare()方法即可为当前线程创建Looper对象,而它的构造器会创建配套的MessageQueue;
  2. 创建Handler对象,重写handleMessage( )方法就可以处理来自于其他线程的信息了!
  3. 调用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 的使用的更多相关文章

  1. Android学习笔记(38):Handler消息传递处理机制

    先说为什么须要Handler: Android的主线程又叫UI线程,用于处理与UI相关的时间.Android仅仅同意在主线程中改动UI组件,当我们在其它线程中须要改动UI界面时.就须要发送消息到主线程 ...

  2. android 学习随笔十七(服务 )

    1.Service 四大组件之一 运行于后台,没有前台界面的组件,用于运行需要在后台运行的代码 可以理解为没有前台的Activity 定义方式:创建java类继承Service,清单文件中注册该类 p ...

  3. Android学习(十七)自定义View控件 TopBar

    一.创建自定义TopBar头部菜单条 实现步骤: 1.在values中添加attrs.xml文件,设置自定义属性. 2.添加Topbar类,继承RelativeLayout,实现具体功能. 3.添加到 ...

  4. 【转】 Pro Android学习笔记(九十):了解Handler(4):Worker线程

    目录(?)[-] worker线程小例子 小例子代码worker线程通过handler实现与主线程的通信 小例子代码继承Handler代码 小例子代码子线程的Runnable 文章转载只能用于非商业性 ...

  5. 【转】 Pro Android学习笔记(八九):了解Handler(3):延迟执行小例子

    目录(?)[-] 小例子 Handler的处理 Activity的代码片段 后台线程和UI的互动 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://b ...

  6. android学习系列:jercy——AI3 的博客

    [android学习之十七]——特色功能2:桌面组件(快捷方式,实时文件夹) 二.桌面组件 1.快捷方式 Android手机上得快捷方式的意思可以以我们实际PC机器上程序的快捷方式来理解.而andro ...

  7. 六、Android学习第五天——Handler的使用(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 六.Android学习第五天——Handler的使用 注意:有很多功能是不 ...

  8. 【转】 Pro Android学习笔记(八八):了解Handler(2):什么是Handler

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 之前我们有一篇很好的博文<Andro ...

  9. IOS学习之十七:Grand Central Dispatch(GCD)编程基础

    IOS学习之十七:Grand Central Dispatch(GCD)编程基础   有过编程经验的人,基本都会接触到多线程这块. 在java中以及Android开发中,大量的后台运行,异步消息队列, ...

  10. 《Android学习指南》目录

    源:<Android学习指南>目录 Android学习指南的内容分类: 分类 描述 0.学习Android必备的Java基础知识 没有Java基础的朋友,请不要先看Android的课程,这 ...

随机推荐

  1. windows: Python安装scipy,scikit-image时提示"no lapack/blas resources found"的解决方法

    解决方案: 最后,解决我遇到的这个问题的解决方案是来自以下链接的答案: http://www.voidcn.com/blog/z6491679/article/p-5740396.html. 另外还有 ...

  2. 1.1- 1.2 hive入门

    一.hive是什么 由Facebook开源用于解决海量结构化日志的数据统计: Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射成一张表, 并提供类SQL查询功能: 构建在Had ...

  3. linux中消息队列<一>

    1 概念 (1)链表式结构组织,存放于内核. (2)通过队列标识来引用. (3)通过一个消息类型来索引指定的数据 2 创建消息队列 #include <sys/msg.h> int msg ...

  4. iOS11 与 iPhone X适配的那些坑(持更中...)

    目录 问题列表 1.适配iPhoneX 屏幕原则 2.适配过程一些常量的设置 3..iPhone X 上运行有黑色区域问题 4.iOS11导航栏适配 5.出现UIScrollview 漂移问题(基本都 ...

  5. MFC的CString使用

    CString没有基类.一个CString对象由可变长度的一队字符组成.CString使用类似于Basic的语法提供函数和操作符.连接和比较操作符以及简化的内存管理使CString对象比普通字符串数组 ...

  6. UGUI DOTween渐隐渐现

    Tween tweenAlpha; tweenAlpha = DOTween.To(() => MaskSpr.fillAmount, x => MaskSpr.fillAmount = ...

  7. 如何使Label有修改功能

    如何使Label有修改功能 之前制作一个项目时需要这样一个功能: 双击Label, 随后Label变为TextBox,用户修改后回车,TextBox变回Label 之前使用WPF做了一个,代码如下: ...

  8. express框架之1

    express框架: 1.依赖中间件 2.接受请求 get / post / use get('/地址' , function(req , resp ){}) post和use 同理 3.非破坏式 4 ...

  9. 在虚拟机中设置NAT模式实现主机和虚拟机的通信

    1.打开虚拟机,对几个节点进行网络连接的设置.虚拟机设置/网络连接,选择“NAT模式” 2.编辑—>虚拟网络编辑器来查看NAT模式中所用到的网段. 从上图可以看出,NAT中的子网IP是192.1 ...

  10. $.each(obj,function(index,value)遍历的学习

    JQuery遍历对象 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...