一、基本概念

   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. 运用Eclipse的Working Set,界面清爽多了

    使用Eclipse的Working Set,界面清爽多了 想必大家的Eclipse里也会有这么多得工程...... 每次工作使用到的项目肯定不会太多...... 每次从这么大数量的工程当中找到自己要使 ...

  2. elmo驱动器使用EAS II配置教程

    一.驱动器接线 1.1驱动器接口: 驱动器接线,需要连接两个接口,一个是反馈接口,一个是STO接口. 反馈接口,我这里使用了elmo驱动器的Port A.这个接口提供5v电源.并且可以输入旋转编码器和 ...

  3. Flink on Yarn模式启动流程源代码分析

    此文已由作者岳猛授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Flink on yarn的启动流程可以参见前面的文章 Flink on Yarn启动流程,下面主要是从源码角 ...

  4. 201621123016 《Java程序设计》第十四周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 使用数据库技术改造你的系统 2.1 简述如何使用数据库技术改造你的系统.要建立什么表?截图你的表设计. 把我原来 ...

  5. 七大查找算法(Python)

    查找算法 -- 简介 查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素.    查找表(Search Table):由同一类型的数据元素构成的集合    ...

  6. 在win下启动memcached

    memcached -m 64 -p 11211 -vvv 设置默认内存64,默认端口11211 ,输出功能及警告错误等信息

  7. Inside Geometry Instancing(下)

    Inside Geometry Instancing(下) http://blog.csdn.net/soilwork/article/details/655858 此教程版权归我所有,仅供个人学习使 ...

  8. django框架知识3

    1.Django安装: 1.安装版本Django1.11.11 2.安装方式:命令行安装   pycharm安装 2.创建Django项目 1.创建方式:cd到你要创建的目录下  然后输入 Djang ...

  9. npm,cnpm,nrm区别

    npm npm(node package manager)是nodejs的包管理器,用于node插件管理(包括安装.卸载.管理依赖等) nrm nrm只是单纯的提供了几个常用的下载包的uri地址,并能 ...

  10. python 基础(四) 函数

    函数 一.什么是函数? 函数是可以实现一些特定功能的 小方法 或者是小程序 优点: 提高 了代码的后期维护 增加了代码的重复使用率 减少了代码量 提高了代码可读性 二.函数的定义 使用 def关键+函 ...