当前位置: 首页 > 编程日记 > 正文

Android Handler介绍

本文转自:http://www.cnblogs.com/keyindex/articles/1822463.html

前言

学习android一段时间了,为了进一步了解android的应用是如何设计开发的,决定详细研究几个开源的android应用。从一些开源应用中吸收点东西,一边进行量的积累,一边探索android的学习研究方向。这里我首先选择了jwood的Standup Timer 项目。本文将把研究的内容笔记整理,建立一个索引列表。

关键词

Android.os.Handler涉及较多的知识点,我把一些关键词列举在下面,将主要介绍Handler:
  • android.os.Handler 、 android.os.Handler.Callback
  • Looper、
  • Threadle、Runnable
  • Message、Message queue

android.os.Handler

Handler在android里负责发送和处理消息。它的主要用途有:
1)按计划发送消息或执行某个Runnanble(使用POST方法);
2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)
默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。

倒计时程序

利用Timer 编写一个倒计时程序,程序使用Timer和TimerTask来完成倒计时,同时使用sendMessages方法发送消息,然后在HanleMessage里更新UI。
Activity布局:

<?
xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center"android:id="@+id/txt"/> <Buttonandroid:id="@+id/btnStartTime"android:text="开始计时"android:layout_width="80dip"android:layout_height="wrap_content" ></Button><Buttonandroid:id="@+id/btnStopTime"android:text="停止计时"android:layout_width="80dip"android:layout_height="wrap_content"/><SeekBar android:id="@+id/SeekBar01" android:layout_width="match_parent" android:layout_height="wrap_content"></SeekBar> </LinearLayout>

这里使用TextView 来显示倒计时的时间变化,两个按钮用于控制时间的开始和停止。SeekBar主要是用于查看线程是否被阻塞(阻塞时无法拖动)。

  @Overridepublicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.main);txt = (TextView) findViewById(R.id.txt);btnStart = (Button) findViewById(R.id.btnStartTime);btnStop = (Button) findViewById(R.id.btnStopTime);Log.d("ThreadId", "onCread:"+ String.valueOf(Thread.currentThread().getId()));myHandler =new Handler(this);btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);}

在onCreate方法中初始化元素个元素,myHandler = new Handler(this); 调用的是  Handler(Handler.Callback callback)构造函数,在回调方法callback中对发送来的消息进行处理(这样我们就不必使用内部类的写法来 重写HandleMessage()方法了),因此Activity必须实现android.os.Handler.Callback 接口。我们还在将onCreate 方法的ThreadId 记录在了Log中用以和消息发送、处理时所作的线程进行比较。
发送消息@Overridepublicvoid onClick(View v) {switch (v.getId()) {case R.id.btnStartTime:startTimer();break;case R.id.btnStopTime:timer.cancel();break;}}privatesynchronizedvoid startTimer() {timer =new Timer();// TimerTask updateTimerValuesTask = new TimerTask() {// @Override// public void run() {// updateTimerValues();// }//// };//自定义的CallBack模式。Task继承自TimerTaskTask updateTimerValuesTask =new Task(this);timer.schedule(updateTimerValuesTask, 1000, 1000);}//执行耗时的倒计时任务。
privatevoid updateTimerValues() {total--;Log.d("ThreadId", "send:"+ String.valueOf(Thread.currentThread().getId()));Message msg=new Message();Bundle date =new Bundle();// 存放数据date.putInt("time", total);msg.setData(date);msg.what=0;myHandler.sendMessage(msg);//另一种写法
//        Message msg=myHandler.obtainMessage();
//        Bundle date = new Bundle();// 存放数据
//        date.putInt("time", total);
//        msg.setData(date);
//        msg.what=0;
//        msg.sendToTarget();
        }@Overridepublicvoid TaskRun() {updateTimerValues();}

实现Button按钮的事件处理以此进入倒计时操作。这里使用的Timer 来执行定时操作(其实我们完全可以另起一个线程)。Task类继承了TimerTask类,里面增加了一个任务处理接口来实现回调模式,应此Activity需要实现该回调的接口 ITaskCallBack(这样做是因为我比较不喜欢内部类的编写方法)。
ICallBack接口和Task类publicinterface ITaskCallBack {void TaskRun();
}publicclass Task extends TimerTask {private ITaskCallBack iTask;public Task(ITaskCallBack iTaskCallBack){super();iTask=iTaskCallBack;}publicvoid setCallBack(ITaskCallBack iTaskCallBack){iTask=iTaskCallBack;}@Overridepublicvoid run() {// TODO Auto-generated method stub
        iTask.TaskRun();}}

这是Java的回调函数的一般写法。
实现CallBack/*** 实现消息处理*/@Overridepublicboolean handleMessage(Message msg) {switch(msg.what){case0:Bundle date=msg.getData();txt.setText(String.valueOf(date.getInt("time")));Log.d("ThreadId", "HandlerMessage:"+ String.valueOf(Thread.currentThread().getId()));Log.d("ThreadId", "msgDate:"+ String.valueOf(date.getInt("time")));break;}returnfalse;}

可以看到 实现android.os.Handler.Callback 接口,其实就是对handleMessage()方法进行重写(和内部类的一个区别是,内部类的返回值是Void)。

运行结果

可以看到在onCreate 方法中线程的ID是1(UI线程) 这与 HandlerMessage 进行消息处理时是所作的线程ID是一样的,而消息发送的线程ID则为8非UI线程。

使用Threadle进行实现

Activity类publicclass ThreadHandlerrActivity extends Activity implements Callback,OnClickListener {private TextView txt;private Button btnStart, btnStop;private Handler myHandler;private TimerThread timerThread;privateint Total=30;/** Called when the activity is first created. */@Overridepublicvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);txt = (TextView) findViewById(R.id.txt);btnStart = (Button) findViewById(R.id.btnStartTime);btnStop = (Button) findViewById(R.id.btnStopTime);Log.d("ThreadId", "onCread:"+ String.valueOf(Thread.currentThread().getId()));myHandler =new Handler(this);btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);}/*** 实现消息处理*/@Overridepublicboolean handleMessage(Message msg) {switch(msg.what){case0:Bundle date=msg.getData();txt.setText(String.valueOf(date.getInt("time")));Log.d("ThreadId", "HandlerMessage:"+ String.valueOf(Thread.currentThread().getId()));Log.d("ThreadId", "msgDate:"+ String.valueOf(date.getInt("time")));break;}returnfalse;}@Overridepublicvoid onClick(View v) {switch (v.getId()) {case R.id.btnStartTime://自定义的线程timerThread=new TimerThread(myHandler,60);timerThread.start();break;case R.id.btnStopTime:timerThread.stop();//timerThread.destroy();
break;}}}

自定义的线程类*** 自定义的线程类,通过传入的Handler,和Total 定期执行耗时操作* @author linzijun**/
publicclass TimerThread extends Thread  {publicint Total=60;public Handler handler;/*** 初始化构造函数* @param mhandler handler 用于发送消息* @param total 总周期*/public TimerThread(Handler mhandler,int total){super();handler=mhandler;Total=total;}@Overridepublicvoid run() {while(true){Total--;if(Total<0)break;try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch block
                e.printStackTrace();}Message msg=new Message();Bundle date =new Bundle();// 存放数据date.putInt("time", Total);msg.setData(date);msg.what=0;Log.d("ThreadId", "Thread:"+ String.valueOf(Thread.currentThread().getId()));handler.sendMessage(msg);}super.run();}}

这里继承了Thread类,也可以直接实现 Runnable接口。

关于POST

Post的各种方法是把一个Runnable发送给消息队列,它将在到达时进行处理。
POSTpublicclass PostHandler extends Activity implements OnClickListener, Runnable {private TextView txt;private Button btnStart, btnStop;private Handler myHandler;private Timer timer;privateint total =60;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stub
super.onCreate(savedInstanceState);setContentView(R.layout.main);txt = (TextView) findViewById(R.id.txt);btnStart = (Button) findViewById(R.id.btnStartTime);btnStop = (Button) findViewById(R.id.btnStopTime);Log.d("ThreadId", "onCread:"+ String.valueOf(Thread.currentThread().getId()));myHandler =new Handler(){@Overridepublicvoid handleMessage(Message msg) {switch(msg.what){case0:Bundle date=msg.getData();txt.setText(String.valueOf(date.getInt("time")));Log.d("ThreadId", "HandlerMessage:"+ String.valueOf(Thread.currentThread().getId()));Log.d("ThreadId", "msgDate:"+ String.valueOf(date.getInt("time")));break;}}};btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {switch (v.getId()) {case R.id.btnStartTime://myHandler.post(this);myHandler.postDelayed(this, 1000);break;case R.id.btnStopTime:break;}}@Overridepublicvoid run() {while(true){total--;if(total<0)break;try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch block
                e.printStackTrace();}Message msg=new Message();Bundle date =new Bundle();// 存放数据date.putInt("time", total);msg.setData(date);msg.what=0;Log.d("ThreadId", "POST:"+ String.valueOf(Thread.currentThread().getId()));myHandler.sendMessage(msg);Log.d("ThreadId", "Thread:"+ String.valueOf(Thread.currentThread().getId()));}}}

使用POST的方式 是将Runnable 一起发送给处理的线程(这里为UI),如果Runnable的操作比较耗时的话那线程将进入阻塞状态。可以看到先运行 Runnable的Run方法 然后在进入 HandleMessage() 。我还尝试了另一种写法,将TimerThreadPOST过去,运行结果是一样的。
POSTpublicclass PostHandler extends Activity implements OnClickListener, Runnable {private TextView txt;private Button btnStart, btnStop;private Handler myHandler;private Timer timer;privateint total =60;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stub
super.onCreate(savedInstanceState);setContentView(R.layout.main);txt = (TextView) findViewById(R.id.txt);btnStart = (Button) findViewById(R.id.btnStartTime);btnStop = (Button) findViewById(R.id.btnStopTime);Log.d("ThreadId", "onCread:"+ String.valueOf(Thread.currentThread().getId()));myHandler =new Handler(){@Overridepublicvoid handleMessage(Message msg) {switch(msg.what){case0:Bundle date=msg.getData();txt.setText(String.valueOf(date.getInt("time")));Log.d("ThreadId", "HandlerMessage:"+ String.valueOf(Thread.currentThread().getId()));Log.d("ThreadId", "msgDate:"+ String.valueOf(date.getInt("time")));break;}}};btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {switch (v.getId()) {case R.id.btnStartTime://myHandler.post(this);myHandler.postDelayed(this, 1000);break;case R.id.btnStopTime:break;}}@Overridepublicvoid run() {while(true){total--;if(total<0)break;try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch block
                e.printStackTrace();}Message msg=new Message();Bundle date =new Bundle();// 存放数据date.putInt("time", total);msg.setData(date);msg.what=0;Log.d("ThreadId", "POST:"+ String.valueOf(Thread.currentThread().getId()));myHandler.sendMessage(msg);Log.d("ThreadId", "Thread:"+ String.valueOf(Thread.currentThread().getId()));}}}

可以说POST的各种方法主要是用于 “按计划发送消息或执行某个Runnanble(使用POST方法)”。

参考文献

android学习笔记之消息机制,异步和多线程
android handler概念解释
SDK

转载于:https://www.cnblogs.com/tianyaxue/p/3149118.html

相关文章:

阿里巴巴一年投三家AR公司,AR购物或是最终目标

阿里巴巴再投资AR公司&#xff0c;一年连续投资超2.2亿美元&#xff0c;它到底想要做什么&#xff1f; 最近&#xff0c;以色列AR眼镜厂商Lumus获得来自阿里巴巴的600万美元的投资。此前&#xff0c;镁客网报道过这家公司在去年12月份获得由广达电脑、HTC和盛大集团投资的300万…

青少年编程竞赛交流群周报(第035周)

2021年10月24日&#xff08;周日&#xff09;晚20:00我们在青少年编程竞赛交流群开展了第三十五期直播活动。 一、直播内容 我们直播活动的主要内容如下&#xff1a; 讲解了上次测试中小朋友们做错的题目 Scratch青少年编程能力等级测试模拟题&#xff08;四级&#xff09;。…

java 接口工程_Java工程师(15)抽象类与接口

抽象类思考下面程序潜在的问题交通工具中定义了4个方法&#xff0c;其中行驶方法内部会依次调用启动、加速、停止方法。由于不同的交通工具&#xff0c;启动的方式差异很大&#xff0c;所以交通工具类中并不实现该方法&#xff0c;而是将其交给子类实现。上述代码的问题&#x…

为什么必须是final的呢?

一个谜团 如果你用过类似guava这种“伪函数式编程”风格的library的话&#xff0c;那下面这种风格的代码对你来说应该不陌生&#xff1a; 1 2 3 4 5 6 7 8 9public void tryUsingGuava() {final int expectedLength 4;Iterables.filter(Lists.newArrayList("123", &…

java mvc view_对Springmvc view层的理解

MVC框架可以把应用清晰明了地分为三个部分&#xff1a;Model层–数据层&#xff0c;View层–视图层&#xff0c;Controller–逻辑层&#xff0c;Model层负责整合数据&#xff0c;View层负责页面渲染&#xff0c;Controller层负责实现业务逻辑。我在这里简单说一下我对MVC框架中…

【优秀作业】粒子群算法

粒子群优化算法 一、概述 粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;的思想来源于对鸟捕食行为的模仿&#xff0c;最初&#xff0c;Reynolds.Heppner 等科学家研究的是鸟类飞行的美学和那些能使鸟群同时突然改变方向&#xff0c;分散…

面向对象进阶2 组合

2019独角兽企业重金招聘Python工程师标准>>> 一&#xff1a;命名空间 class Person:Country 中国人 # 静态变量print(Person.Country) alex Person() # 创建了一个空的命名空间 alex.name alex # 对象 alex.Country 泰国人 egon Person() egon.name ego…

Android基础知识之Manifest文件的组织结构

原文&#xff1a;http://android.eoe.cn/topic/android_sdk 是AndroidManifest.xml文件中的根标签&#xff0c;她必须包含一个标签和指定的xmlns:android、 package两个属性。 属性&#xff1a; xmlns:android定义了Android的命名空间。这个属性一般可以设置为&#xff1a;&quo…

java类的注释模板_IDEA添加Java类注释模版的方法

本文介绍了idea添加java类注释模版的方法&#xff0c;分享给大家&#xff0c;具体如下&#xff1a;idea版本&#xff1a;intellij idea 2017.2.5 x64eclipse能在类上方输入/**,回车添加类注释模版&#xff0c;但idea没有默认添加这个功能&#xff0c;需要做一些设置。下面介绍三…

POJ 2586 Y2K Accounting Bug(贪心)

题目连接&#xff1a;http://poj.org/problem?id2586 题意&#xff1a;某公司要统计全年盈利状况&#xff0c;对于每一个月来说&#xff0c;如果盈利则盈利S&#xff0c;如果亏空则亏空D。公司每五个月进行一次统计&#xff0c;全年共统计8次(1-5、2-6、3-7、4-8、5-9、6-10、…

【组队学习】10月份微信图文索引

10月份微信图文索引 一、组队学习相关 周报&#xff1a; Datawhale组队学习周报&#xff08;第036周&#xff09;Datawhale组队学习周报&#xff08;第035周&#xff09;Datawhale组队学习周报&#xff08;第034周&#xff09;Datawhale组队学习周报&#xff08;第033周&…

java spring scope_如何在Spring中自定义scope的方法示例

大家对于 Spring 的 scope 应该都不会默认。所谓 scope&#xff0c;字面理解就是“作用域”、“范围”&#xff0c;如果一个 bean 的 scope 配置为 singleton&#xff0c;则从容器中获取 bean 返回的对象都是相同的&#xff1b;如果 scope 配置为prototype&#xff0c;则每次返…

学习ExtJS4 常用控件

ExtJS组件配置方式介绍 1.使用逗号分隔参数列表配置组件 首先来看一个简单的逗号分隔参数列表的例子。这个例子非常简单&#xff0c;它用来显示信息提示框。 2.使用Json对象配置组件 接下来看一个使用Json对象配置组件的例子&#xff0c;很多地方习惯性称之为配…

青少年编程竞赛交流群周报(第036周)

2021年10月31日&#xff08;周日&#xff09;晚20:00我们在青少年编程竞赛交流群开展了第三十六期直播活动。 一、直播内容 我们直播活动的主要内容如下&#xff1a; 讲解了上次测试中小朋友们做错的题目 Scratch青少年编程能力等级测试模拟题&#xff08;四级&#xff09;。…

中国电信打造“三朵云”战略 助力互联网+医疗发展

随着云计算、大数据的快速发展&#xff0c;全行业上云成为一个趋势&#xff0c;在健康医疗这个领域&#xff0c;应大势之趋&#xff0c;纷纷构建医疗云。近日&#xff0c;中国电信医疗云专区北京节点发布会在京顺利召开&#xff0c;会后北京电信副总经理项煌妹接受了中国IDC圈记…

python 数据类笔试题_一道 Python 类的笔试题详解

r {}class C(object):def __init__(self, a, b):self.a aself.b bif b a:orig super(C, cls)r[cls.instance] 1a C(1, a)b C(1, a)c C(1, b)l [a, b, c]for i in l:if i not in r:r[i] 1else:r[i] 1assert r[a] 2assert r[b] 2assert r[c] 1原题目要求如下&…

【优秀作业】粒子群算法(Python)

粒子群优化算法 一、概述 粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;的思想来源于对鸟捕食行为的模仿&#xff0c;最初&#xff0c;Reynolds.Heppner 等科学家研究的是鸟类飞行的美学和那些能使鸟群同时突然改变方向&#xff0c;分散…

警惕企业中的五种虚假执行力

第一种虚假执行力&#xff1a;无条件服从——只强调员工“服从”&#xff0c;不强调员工的智慧 很多人讲执行力&#xff0c;很喜欢强调员工的无条件服从。这种观念是OEM(代工生产)制造业时代的产物。实际上这是一种基于“规模制造”的虚假执行力&#xff0c;其本质是把人当成了…

真实记录疑似Linux病毒导致服务器 带宽跑满的解决过程

案例描述 由于最近我在重构之前的APP&#xff0c;需要和server端进行数据交互&#xff0c;发现有一个现象&#xff0c;那么就是隔1~2天总会发生获取数据超时的问题&#xff0c;而且必须要重启服务器才能解决。早在之前&#xff0c;我有留意到这个问题&#xff0c;但是由于这个服…

java集合总结_Java中集合总结

Java数组的长度是固定的&#xff0c;为了使程序能够方便地存储和操作数目不固定的一组数据&#xff0c;JDK类库提供了Java集合&#xff0c;这些集合类都位于java.util包中&#xff0c;但是与数组不同的是&#xff0c;集合中不能存放基本类型数据&#xff0c;而只能存放对象的引…

区块链基本解读

最近看着这个区块链&#xff0c;稍有新得&#xff0c;写下菜鸟自己的理解&#xff0c;希望大牛多多指点。 总体心得&#xff0c;如果互联网技术解决的是通讯问题的话&#xff0c;区块链技术解决的是信任问题。 下面举个日常例子&#xff1a;打赌 比如A和B赌石头是否为天然玉石&…

PDO防注入原理分析以及使用PDO的注意事项 (转)

我们都知道&#xff0c;只要合理正确使用PDO,可以基本上防止SQL注入的产生&#xff0c;本文主要回答以下两个问题&#xff1a; 为什么要使用PDO而不是mysql_connect&#xff1f; 为何PDO能防注入&#xff1f; 使用PDO防注入的时候应该特别注意什么? 一、为何要优先使用PDO? P…

LSGO软件技术团队招新 线下组队学习

团队招新 LSGO软件技术团队&#xff08;Dreamtech算法组&#xff09;成立于2010年09月&#xff0c;团队主要从事地理信息系统、管理信息系统、计算机视觉等领域的应用开发&#xff0c;团队同时具有培养学生的重要职能&#xff0c;毕业学生分布在IBM、百度、阿里、腾讯、京东、…

java spring 配置文件_[Java教程]Spring配置文件

[Java教程]Spring配置文件02016-03-19 00:00:08Spring配置文件是集成了Spring框架的项目的核心&#xff0c;引擎从哪里开始&#xff0c;中间都执行了哪些操作&#xff0c;小谈一下它的执行流程。容器先是加载web.接着是applicationContext.一种方法是加入ContextLoaderServlet这…

王子朝:一种高效且容错的方法用于协作车辆定位

王子朝是华北电力大学计算机系大四的学生&#xff0c;Dreamtech成员&#xff0c;参加了多期Dreamtech与Datawhale联合组织的组队学习活动&#xff0c;现保送西安电子科技大学深造。 这篇图文是他在线下组队学习时&#xff0c;为大家分享自己所看论文的总结。 希望参与我们组队…

python文件句柄_Python文件操作

classfile(object):def close(self): #real signature unknown; restored from __doc__关闭文件"""close() -> None or (perhaps) an integer. Close the file.Sets data attribute .closed to True. A closed file cannot be used forfurther I/O operation…

XML简单的增改删操作

XML文件的简单增改删&#xff0c;每一个都可以单独拿出来使用。 新创建XML文件&#xff0c;<?xmlversion"1.0"encoding"utf-8"?> <bookstore> <bookgenre"fantasy"ISBN"2-3631-4"> <title>Oberons Legacy&l…

javascript推荐书籍

WEB前端研发工程师&#xff0c;在国内算是一个朝阳职业&#xff0c;这个领域没有学校的正规教育&#xff0c;大多数人都是靠自己自学成才。本文主要介绍自己从事web开发以来(从大二至今)看过的书籍和自己的成长过程&#xff0c;目的是给想了解 JavaScript或者是刚接触JavaScrip…