android的Handler

 

前言

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

关键词

  Android.os.Handler涉及较多的知识点,我把一些关键词列举在下面,将主要介绍Handler:

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布局:
  1. Layout
  2.  
  3. <?xml version="1.0" encoding="utf-8"?>
  4. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  5. android:orientation="vertical"
  6. android:layout_width="fill_parent"
  7. android:layout_height="fill_parent"
  8. >
  9. <TextView
  10. android:layout_width="fill_parent"
  11. android:layout_height="wrap_content"
  12. android:layout_gravity="center"
  13. android:id="@+id/txt"
  14. />
  15. <Button
  16. android:id="@+id/btnStartTime"
  17. android:text="开始计时"
  18. android:layout_width="80dip"
  19. android:layout_height="wrap_content"
  20.  
  21. ></Button>
  22. <Button
  23. android:id="@+id/btnStopTime"
  24. android:text="停止计时"
  25. android:layout_width="80dip"
  26. android:layout_height="wrap_content"
  27. />
  28.  
  29. <SeekBar android:id="@+id/SeekBar01" android:layout_width="match_parent" android:layout_height="wrap_content"></SeekBar>
  30. </LinearLayout>

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

  1. onCreate
  2.  
  3. @Override
  4. publicvoid onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.main);
  7. txt = (TextView) findViewById(R.id.txt);
  8. btnStart = (Button) findViewById(R.id.btnStartTime);
  9. btnStop = (Button) findViewById(R.id.btnStopTime);
  10. Log.d("ThreadId", "onCread:"
  11. + String.valueOf(Thread.currentThread().getId()));
  12. myHandler =new Handler(this);
  13.  
  14. btnStart.setOnClickListener(this);
  15. btnStop.setOnClickListener(this);
  16.  
  17. }

在onCreate方法中初始化元素个元素,myHandler = new Handler(this); 调用的是  Handler(Handler.Callback callback)构造函数,在回调方法callback中对发送来的消息进行处理(这样我们就不必使用内部类的写法来 重写HandleMessage()方法了),因此Activity必须实现android.os.Handler.Callback 接口。我们还在将onCreate 方法的ThreadId 记录在了Log中用以和消息发送、处理时所作的线程进行比较。

  1. 发送消息
  2.  
  3. @Override
  4. publicvoid onClick(View v) {
  5. switch (v.getId()) {
  6. case R.id.btnStartTime:
  7. startTimer();
  8. break;
  9. case R.id.btnStopTime:
  10. timer.cancel();
  11.  
  12. break;
  13. }
  14.  
  15. }
  16.  
  17. privatesynchronizedvoid startTimer() {
  18.  
  19. timer =new Timer();
  20. // TimerTask updateTimerValuesTask = new TimerTask() {
  21. // @Override
  22. // public void run() {
  23. // updateTimerValues();
  24. // }
  25. //
  26. // };
  27. //自定义的CallBack模式。Task继承自TimerTask
  28. Task updateTimerValuesTask =new Task(this);
  29.  
  30. timer.schedule(updateTimerValuesTask, , );
  31. }
  32.  
  33. //执行耗时的倒计时任务。
  34. privatevoid updateTimerValues() {
  35. total--;
  36.  
  37. Log.d("ThreadId", "send:"
  38. + String.valueOf(Thread.currentThread().getId()));
  39.  
  40. Message msg=new Message();
  41. Bundle date =new Bundle();// 存放数据
  42. date.putInt("time", total);
  43. msg.setData(date);
  44. msg.what=;
  45. myHandler.sendMessage(msg);
  46.  
  47. //另一种写法
  48. // Message msg=myHandler.obtainMessage();
  49. // Bundle date = new Bundle();// 存放数据
  50. // date.putInt("time", total);
  51. // msg.setData(date);
  52. // msg.what=0;
  53. // msg.sendToTarget();
  54.  
  55. }
  56.  
  57. @Override
  58. publicvoid TaskRun() {
  59. updateTimerValues();
  60.  
  61. }

实现Button按钮的事件处理以此进入倒计时操作。这里使用的Timer 来执行定时操作(其实我们完全可以另起一个线程)。Task类继承了TimerTask类,里面增加了一个任务处理接口来实现回调模式,应此Activity需要实现该回调的接口 ITaskCallBack(这样做是因为我比较不喜欢内部类的编写方法)。

  1. ICallBack接口和Task
  2.  
  3. publicinterface ITaskCallBack {
  4.  
  5. void TaskRun();
  6. }
  7.  
  8. publicclass Task extends TimerTask {
  9.  
  10. private ITaskCallBack iTask;
  11.  
  12. public Task(ITaskCallBack iTaskCallBack)
  13. {
  14. super();
  15. iTask=iTaskCallBack;
  16. }
  17.  
  18. publicvoid setCallBack(ITaskCallBack iTaskCallBack)
  19. {
  20. iTask=iTaskCallBack;
  21. }
  22. @Override
  23. publicvoid run() {
  24. // TODO Auto-generated method stub
  25. iTask.TaskRun();
  26. }
  27.  
  28. }

这是Java的回调函数的一般写法。

  1. 实现CallBack
  2.  
  3. /**
  4. * 实现消息处理
  5. */
  6. @Override
  7. publicboolean handleMessage(Message msg) {
  8.  
  9. switch(msg.what)
  10. {
  11. case0:
  12. Bundle date=msg.getData();
  13. txt.setText(String.valueOf(date.getInt("time")));
  14.  
  15. Log.d("ThreadId", "HandlerMessage:"
  16. + String.valueOf(Thread.currentThread().getId()));
  17. Log.d("ThreadId", "msgDate:"
  18. + String.valueOf(date.getInt("time")));
  19. break;
  20.  
  21. }
  22. returnfalse;
  23. }

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

运行结果

  可以看到在onCreate 方法中线程的ID是1(UI线程) 这与 HandlerMessage 进行消息处理时是所作的线程ID是一样的,而消息发送的线程ID则为8非UI线程。
 
使用Threadle进行实现
  1. Activity
  2.  
  3. publicclass ThreadHandlerrActivity extends Activity implements Callback,
  4. OnClickListener {
  5.  
  6. private TextView txt;
  7. private Button btnStart, btnStop;
  8. private Handler myHandler;
  9. private TimerThread timerThread;
  10. privateint Total=;
  11.  
  12. /** Called when the activity is first created. */
  13. @Override
  14. publicvoid onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.main);
  17. txt = (TextView) findViewById(R.id.txt);
  18. btnStart = (Button) findViewById(R.id.btnStartTime);
  19. btnStop = (Button) findViewById(R.id.btnStopTime);
  20. Log.d("ThreadId", "onCread:"
  21. + String.valueOf(Thread.currentThread().getId()));
  22. myHandler =new Handler(this);
  23.  
  24. btnStart.setOnClickListener(this);
  25. btnStop.setOnClickListener(this);
  26.  
  27. }
  28.  
  29. /**
  30. * 实现消息处理
  31. */
  32. @Override
  33. publicboolean handleMessage(Message msg) {
  34.  
  35. switch(msg.what)
  36. {
  37. case0:
  38. Bundle date=msg.getData();
  39. txt.setText(String.valueOf(date.getInt("time")));
  40.  
  41. Log.d("ThreadId", "HandlerMessage:"
  42. + String.valueOf(Thread.currentThread().getId()));
  43. Log.d("ThreadId", "msgDate:"
  44. + String.valueOf(date.getInt("time")));
  45. break;
  46.  
  47. }
  48. returnfalse;
  49. }
  50.  
  51. @Override
  52. publicvoid onClick(View v) {
  53. switch (v.getId()) {
  54. case R.id.btnStartTime:
  55. //自定义的线程
  56. timerThread=new TimerThread(myHandler,);
  57. timerThread.start();
  58.  
  59. break;
  60. case R.id.btnStopTime:
  61. timerThread.stop();
  62. //timerThread.destroy();
  63. break;
  64. }
  65.  
  66. }
  67.  
  68. }
  1. 自定义的线程类
  2.  
  3. **
  4. * 自定义的线程类,通过传入的Handler,和Total 定期执行耗时操作
  5. * @author linzijun
  6. *
  7. */
  8. publicclass TimerThread extends Thread {
  9.  
  10. publicint Total=;
  11. public Handler handler;
  12. /**
  13. * 初始化构造函数
  14. * @param mhandler handler 用于发送消息
  15. * @param total 总周期
  16. */
  17. public TimerThread(Handler mhandler,int total)
  18. {
  19. super();
  20. handler=mhandler;
  21. Total=total;
  22. }
  23. @Override
  24. publicvoid run() {
  25.  
  26. while(true)
  27. {
  28. Total--;
  29. if(Total<)
  30. break;
  31. try {
  32. Thread.sleep();
  33. } catch (InterruptedException e) {
  34. // TODO Auto-generated catch block
  35. e.printStackTrace();
  36. }
  37. Message msg=new Message();
  38. Bundle date =new Bundle();// 存放数据
  39. date.putInt("time", Total);
  40. msg.setData(date);
  41. msg.what=;
  42. Log.d("ThreadId", "Thread:"
  43. + String.valueOf(Thread.currentThread().getId()));
  44. handler.sendMessage(msg);
  45.  
  46. }
  47.  
  48. super.run();
  49. }
  50.  
  51. }

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

关于POST

Post的各种方法是把一个Runnable发送给消息队列,它将在到达时进行处理。
  1. POST
  2.  
  3. publicclass PostHandler extends Activity implements OnClickListener, Runnable {
  4.  
  5. private TextView txt;
  6. private Button btnStart, btnStop;
  7. private Handler myHandler;
  8. private Timer timer;
  9. privateint total =;
  10.  
  11. @Override
  12. protectedvoid onCreate(Bundle savedInstanceState) {
  13. // TODO Auto-generated method stub
  14. super.onCreate(savedInstanceState);
  15.  
  16. setContentView(R.layout.main);
  17. txt = (TextView) findViewById(R.id.txt);
  18. btnStart = (Button) findViewById(R.id.btnStartTime);
  19. btnStop = (Button) findViewById(R.id.btnStopTime);
  20. Log.d("ThreadId", "onCread:"
  21. + String.valueOf(Thread.currentThread().getId()));
  22. myHandler =new Handler()
  23. {
  24.  
  25. @Override
  26. publicvoid handleMessage(Message msg) {
  27. switch(msg.what)
  28. {
  29. case0:
  30. Bundle date=msg.getData();
  31. txt.setText(String.valueOf(date.getInt("time")));
  32.  
  33. Log.d("ThreadId", "HandlerMessage:"
  34. + String.valueOf(Thread.currentThread().getId()));
  35. Log.d("ThreadId", "msgDate:"
  36. + String.valueOf(date.getInt("time")));
  37. break;
  38.  
  39. }
  40.  
  41. }
  42.  
  43. };
  44.  
  45. btnStart.setOnClickListener(this);
  46. btnStop.setOnClickListener(this);
  47. }
  48.  
  49. @Override
  50. publicvoid onClick(View v) {
  51. switch (v.getId()) {
  52. case R.id.btnStartTime:
  53. //myHandler.post(this);
  54. myHandler.postDelayed(this, );
  55. break;
  56. case R.id.btnStopTime:
  57.  
  58. break;
  59. }
  60.  
  61. }
  62.  
  63. @Override
  64. publicvoid run() {
  65. while(true)
  66. {
  67. total--;
  68. if(total<)
  69. break;
  70. try {
  71. Thread.sleep();
  72. } catch (InterruptedException e) {
  73. // TODO Auto-generated catch block
  74. e.printStackTrace();
  75. }
  76. Message msg=new Message();
  77. Bundle date =new Bundle();// 存放数据
  78. date.putInt("time", total);
  79. msg.setData(date);
  80. msg.what=;
  81. Log.d("ThreadId", "POST:"
  82. + String.valueOf(Thread.currentThread().getId()));
  83. myHandler.sendMessage(msg);
  84. Log.d("ThreadId", "Thread:"
  85. + String.valueOf(Thread.currentThread().getId()));
  86.  
  87. }
  88.  
  89. }
  90.  
  91. }

使用POST的方式 是将Runnable 一起发送给处理的线程(这里为UI),如果Runnable的操作比较耗时的话那线程将进入阻塞状态。可以看到先运行 Runnable的Run方法 然后在进入 HandleMessage() 。我还尝试了另一种写法,将TimerThreadPOST过去,运行结果是一样的。

  1. 代码
  2.  
  3. package zijunlin.me;
  4.  
  5. import java.util.Timer;
  6.  
  7. import android.app.Activity;
  8. import android.os.Bundle;
  9. import android.os.Handler;
  10. import android.os.Message;
  11. import android.util.Log;
  12. import android.view.View;
  13. import android.view.View.OnClickListener;
  14. import android.widget.Button;
  15. import android.widget.TextView;
  16.  
  17. publicclass PostHandler extends Activity implements OnClickListener, Runnable {
  18.  
  19. private TextView txt;
  20. private Button btnStart, btnStop;
  21. private Handler myHandler;
  22. private Timer timer;
  23. privateint total =;
  24. private TimerThread timerThread;
  25.  
  26. @Override
  27. protectedvoid onCreate(Bundle savedInstanceState) {
  28. // TODO Auto-generated method stub
  29. super.onCreate(savedInstanceState);
  30.  
  31. setContentView(R.layout.main);
  32. txt = (TextView) findViewById(R.id.txt);
  33. btnStart = (Button) findViewById(R.id.btnStartTime);
  34. btnStop = (Button) findViewById(R.id.btnStopTime);
  35. Log.d("ThreadId", "onCread:"
  36. + String.valueOf(Thread.currentThread().getId()));
  37. myHandler =new Handler()
  38. {
  39.  
  40. @Override
  41. publicvoid handleMessage(Message msg) {
  42. switch(msg.what)
  43. {
  44. case0:
  45. Bundle date=msg.getData();
  46. txt.setText(String.valueOf(date.getInt("time")));
  47.  
  48. Log.d("ThreadId", "HandlerMessage:"
  49. + String.valueOf(Thread.currentThread().getId()));
  50. Log.d("ThreadId", "msgDate:"
  51. + String.valueOf(date.getInt("time")));
  52. break;
  53.  
  54. }
  55.  
  56. }
  57.  
  58. };
  59.  
  60. btnStart.setOnClickListener(this);
  61. btnStop.setOnClickListener(this);
  62. }
  63.  
  64. @Override
  65. publicvoid onClick(View v) {
  66. switch (v.getId()) {
  67. case R.id.btnStartTime:
  68. //myHandler.post(this);
  69. //myHandler.postDelayed(this, 1000);
  70. timerThread=new TimerThread(myHandler,);
  71.  
  72. myHandler.post(timerThread);
  73. break;
  74. case R.id.btnStopTime:
  75.  
  76. break;
  77. }
  78.  
  79. }
  80.  
  81. @Override
  82. publicvoid run() {
  83. while(true)
  84. {
  85. total--;
  86. if(total<)
  87. break;
  88. try {
  89. Thread.sleep();
  90. } catch (InterruptedException e) {
  91. // TODO Auto-generated catch block
  92. e.printStackTrace();
  93. }
  94. Message msg=new Message();
  95. Bundle date =new Bundle();// 存放数据
  96. date.putInt("time", total);
  97. msg.setData(date);
  98. msg.what=;
  99. Log.d("ThreadId", "POST:"
  100. + String.valueOf(Thread.currentThread().getId()));
  101. myHandler.sendMessage(msg);
  102. Log.d("ThreadId", "Thread:"
  103. + String.valueOf(Thread.currentThread().getId()));
  104.  
  105. }
  106.  
  107. }
  108.  
  109. }

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

本文来源:http://www.cnblogs.com/keyindex/archive/

android中的Handler的更多相关文章

  1. Android中使用Handler造成内存泄露的分析和解决

    什么是内存泄露?Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向 ...

  2. Android中使用Handler造成内存泄露

    1.什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用 ...

  3. Android中的Handler的机制与用法详解

    概述: 很多android初学者对android 中的handler不是很明白,其实Google参考了Windows的消息处理机制, 在Android系统中实现了一套类似的消息处理机制.在下面介绍ha ...

  4. android中的Handler和Runnable

    最近在做一个项目,在网络请求时考虑用Handler进行处理,然后就研究了一下Handler和Runnable 首先在看一下java中的Runnable The Runnable interface s ...

  5. Android中利用Handler实现消息的分发机制(三)

    在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去 ...

  6. 转:Android中的Handler的机制与用法详解

    注:Message类的用法: message的几个参数都可以携带数据,其中arg1与arg2可以携带int类型,what是用户自定义的int型,这样接受者可以了解这个消息的信息. 说明:使用Messa ...

  7. 深入源代码解析Android中的Handler,Message,MessageQueue,Looper

    本文主要是对Handler和消息循环的实现原理进行源代码分析.假设不熟悉Handler能够參见博文< Android中Handler的使用>,里面对Android为何以引入Handler机 ...

  8. Android中关于Handler的若干思考

    在之前的博文中,讲过一些和Handler有关的知识,例如: Android 多线程----AsyncTask异步任务详解 Android多线程----异步消息处理机制之Handler详解 今天再把Ha ...

  9. 深入探索Android中的Handler

    一.概述 1. 什么是Handler Handler是Android消息机制的上层接口,它为我们封装了许多底层的细节,让我们能够很方便的使用底层的消息机制.Handler的最常见应用场景之一便是通过H ...

  10. Android中的Handler机制

    直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,如下错 误:android.view.ViewRoot$CalledFromWrongThreadException: ...

随机推荐

  1. 端午小长假--前端基础学起来04CSS选择器

    定义: 选择器{ 样式: } 选择器指明{}中的样式的作用对象,即作用于网页中的哪些元素 <head><meta http-equiv="Content-Type" ...

  2. Oracle GoldenGate Veridata 12.1.3已经发布

    通过GoldenGate Veridata 12.1.3,现在只需要一键点击即可修复数据复制后不一致的数据. veridata 架构

  3. jQuery 自定义扩展,与$冲突处理

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. hadoop版本和位数的查看方法

    目前针对apache hadoop更新的版本较多,由此而产生了两个方面的问题: 1.如何查看运行的集群当中的hadoop的版本的问题. 2.如何查看运行集群当中的hadoop的位数 下面详细的介绍一下 ...

  5. <转>thinkphp的各种内部函数 D()、F()、S()、C()、L()、A()、I()详解

    D.F.S.C.L.A.I 他们都在functions.php这个文件家下面我分别说明一下他们的功能 D() 加载Model类M() 加载Model类 A() 加载Action类L() 获取语言定义C ...

  6. 国内android帮助文档镜像网站---http://wear.techbrood.com/develop/index.html

    http://wear.techbrood.com/develop/index.html

  7. 玩转渗透神器Kali:Kali Linux作为主系统使用的正确姿势TIPS

    Kali Linux 前身是著名渗透测试系统BackTrack ,是一个基于 Debian 的 Linux 发行版,包含很多安全和取证方面的相关工具. 本文假设你在新装好的kali linux环境下… ...

  8. 北大poj-1001

    Description Problems involving the computation of exact values of very large magnitude and precision ...

  9. C++11 不抛异常的new operator

    在google cpp style guide里面明确指出:we don't use exceptions C++11的noexcept关键字为这种选择提供了便利. C++11以前,提及malloc和 ...

  10. UITableView详解(1)

    一,UITableView控件使用必备,红色部分是易错点和难点 首先创建一个项目,要使用UITableView就需要实现协议<UITableViewDataSource>,数据源协议主要完 ...