前言
  学习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布局:
layout
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:layout_gravity="center"
  11. android:id="@+id/txt"
  12. />
  13. <Button
  14. android:id="@+id/btnStartTime"
  15. android:text="开始计时"
  16. android:layout_width="80dip"
  17. android:layout_height="wrap_content"

  18. ></Button>
  19. <Button
  20. android:id="@+id/btnStopTime"
  21. android:text="停止计时"
  22. android:layout_width="80dip"
  23. android:layout_height="wrap_content"
  24. />

  25. <SeekBar android:id="@+id/SeekBar01" android:layout_width="match_parent" android:layout_height="wrap_content"></SeekBar>
  26. </LinearLayout>
复制代码 这里使用TextView 来显示倒计时的时间变化,两个按钮用于控制时间的开始和停止。SeekBar主要是用于查看线程是否被阻塞(阻塞时无法拖动)。
  1. onCreate
  2. @Override
  3. public void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.main);
  6. txt = (TextView) findViewById(R.id.txt);
  7. btnStart = (Button) findViewById(R.id.btnStartTime);
  8. btnStop = (Button) findViewById(R.id.btnStopTime);
  9. Log.d("ThreadId", "onCread:"
  10. + String.valueOf(Thread.currentThread().getId()));
  11. myHandler = new Handler(this);

  12. btnStart.setOnClickListener(this);
  13. btnStop.setOnClickListener(this);

  14. }
复制代码 在onCreate方法中初始化元素个元素,myHandler = new Handler(this); 调用的是Handler(Handler.Callback callback)构造函数,在回调方法callback中对发送来的消息进行处理(这样我们就不必使用内部类的写法来 重写HandleMessage()方法了),因此Activity必须实现 android.os.Handler.Callback 接口。我们还在将onCreate 方法的ThreadId 记录在了Log中用以和消息发送、处理时所作的线程进行比较。
发送消息
  1. @Override
  2. public void onClick(View v) {
  3. switch (v.getId()) {
  4. case R.id.btnStartTime:
  5. startTimer();
  6. break;
  7. case R.id.btnStopTime:
  8. timer.cancel();

  9. break;
  10. }

  11. }

  12. private synchronized void startTimer() {

  13. timer = new Timer();
  14. // TimerTask updateTimerValuesTask = new TimerTask() {
  15. // @Override
  16. // public void run() {
  17. // updateTimerValues();
  18. // }
  19. //
  20. // };
  21. //自定义的CallBack模式。Task继承自TimerTask
  22. Task updateTimerValuesTask = new Task(this);

  23. timer.schedule(updateTimerValuesTask, 1000, 1000);
  24. }

  25. //执行耗时的倒计时任务。
  26. private void updateTimerValues() {
  27. total--;

  28. Log.d("ThreadId", "send:"
  29. + String.valueOf(Thread.currentThread().getId()));

  30. Message msg=new Message();
  31. Bundle date = new Bundle();// 存放数据
  32. date.putInt("time", total);
  33. msg.setData(date);
  34. msg.what=0;
  35. myHandler.sendMessage(msg);

  36. //另一种写法
  37. // Message msg=myHandler.obtainMessage();
  38. // Bundle date = new Bundle();// 存放数据
  39. // date.putInt("time", total);
  40. // msg.setData(date);
  41. // msg.what=0;
  42. // msg.sendToTarget();

  43. }

  44. @Override
  45. public void TaskRun() {
  46. updateTimerValues();

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

  2. void TaskRun();
  3. }



  4. public class Task extends TimerTask {

  5. private ITaskCallBack iTask;

  6. public Task(ITaskCallBack iTaskCallBack)
  7. {
  8. super();
  9. iTask=iTaskCallBack;
  10. }

  11. public void setCallBack(ITaskCallBack iTaskCallBack)
  12. {
  13. iTask=iTaskCallBack;
  14. }
  15. @Override
  16. public void run() {
  17. // TODO Auto-generated method stub
  18. iTask.TaskRun();
  19. }

  20. }
复制代码 这是Java的回调函数的一般写法。
实现CallBack
  1. /**
  2. * 实现消息处理
  3. */
  4. @Override
  5. public boolean handleMessage(Message msg) {

  6. switch(msg.what)
  7. {
  8. case 0:
  9. Bundle date=msg.getData();
  10. txt.setText(String.valueOf(date.getInt("time")));

  11. Log.d("ThreadId", "HandlerMessage:"
  12. + String.valueOf(Thread.currentThread().getId()));
  13. Log.d("ThreadId", "msgDate:"
  14. + String.valueOf(date.getInt("time")));
  15. break;

  16. }
  17. return false;
  18. }
复制代码   可以看到 实现 android.os.Handler.Callback 接口,其实就是对handleMessage()方法进行重写(和内部类的一个区别是,内部类的返回值是Void)。
运行结果

  可以看到在onCreate 方法中线程的ID是1(UI线程) 这与 HandlerMessage 进行消息处理时是所作的线程ID是一样的,而消息发送的线程ID则为8非UI线程。
使用Threadle进行实现
Activity类
  1. public class ThreadHandlerrActivity extends Activity implements Callback,
  2. OnClickListener {

  3. private TextView txt;
  4. private Button btnStart, btnStop;
  5. private Handler myHandler;
  6. private TimerThread timerThread;
  7. private int Total=30;


  8. /** Called when the activity is first created. */
  9. @Override
  10. public void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.main);
  13. txt = (TextView) findViewById(R.id.txt);
  14. btnStart = (Button) findViewById(R.id.btnStartTime);
  15. btnStop = (Button) findViewById(R.id.btnStopTime);
  16. Log.d("ThreadId", "onCread:"
  17. + String.valueOf(Thread.currentThread().getId()));
  18. myHandler = new Handler(this);


  19. btnStart.setOnClickListener(this);
  20. btnStop.setOnClickListener(this);

  21. }

  22. /**
  23. * 实现消息处理
  24. */
  25. @Override
  26. public boolean handleMessage(Message msg) {

  27. switch(msg.what)
  28. {
  29. case 0:
  30. Bundle date=msg.getData();
  31. txt.setText(String.valueOf(date.getInt("time")));

  32. Log.d("ThreadId", "HandlerMessage:"
  33. + String.valueOf(Thread.currentThread().getId()));
  34. Log.d("ThreadId", "msgDate:"
  35. + String.valueOf(date.getInt("time")));
  36. break;

  37. }
  38. return false;
  39. }

  40. @Override
  41. public void onClick(View v) {
  42. switch (v.getId()) {
  43. case R.id.btnStartTime:
  44. //自定义的线程
  45. timerThread=new TimerThread(myHandler,60);
  46. timerThread.start();

  47. break;
  48. case R.id.btnStopTime:
  49. timerThread.stop();
  50. //timerThread.destroy();
  51. break;
  52. }

  53. }




  54. }
复制代码 自定义的线程类
  1. **
  2. * 自定义的线程类,通过传入的Handler,和Total 定期执行耗时操作
  3. * @author linzijun
  4. *
  5. */
  6. public class TimerThread extends Thread{

  7. public int Total=60;
  8. public Handler handler;
  9. /**
  10. * 初始化构造函数
  11. * @param mhandler handler 用于发送消息
  12. * @param total 总周期
  13. */
  14. public TimerThread(Handler mhandler,int total)
  15. {
  16. super();
  17. handler=mhandler;
  18. Total=total;
  19. }
  20. @Override
  21. public void run() {

  22. while(true)
  23. {
  24. Total--;
  25. if(Total<0)
  26. break;
  27. try {
  28. Thread.sleep(1000);
  29. } catch (InterruptedException e) {
  30. // TODO Auto-generated catch block
  31. e.printStackTrace();
  32. }
  33. Message msg=new Message();
  34. Bundle date = new Bundle();// 存放数据
  35. date.putInt("time", Total);
  36. msg.setData(date);
  37. msg.what=0;
  38. Log.d("ThreadId", "Thread:"
  39. + String.valueOf(Thread.currentThread().getId()));
  40. handler.sendMessage(msg);


  41. }

  42. super.run();
  43. }



  44. }
复制代码 这里继承了Thread类,也可以直接实现 Runnable接口。
关于POST
  Post的各种方法是把一个Runnable发送给消息队列,它将在到达时进行处理。
POST
  1. public class PostHandler extends Activity implements OnClickListener, Runnable {

  2. private TextView txt;
  3. private Button btnStart, btnStop;
  4. private Handler myHandler;
  5. private Timer timer;
  6. private int total = 60;


  7. @Override
  8. protected void onCreate(Bundle savedInstanceState) {
  9. // TODO Auto-generated method stub
  10. super.onCreate(savedInstanceState);

  11. setContentView(R.layout.main);
  12. txt = (TextView) findViewById(R.id.txt);
  13. btnStart = (Button) findViewById(R.id.btnStartTime);
  14. btnStop = (Button) findViewById(R.id.btnStopTime);
  15. Log.d("ThreadId", "onCread:"
  16. + String.valueOf(Thread.currentThread().getId()));
  17. myHandler = new Handler()
  18. {

  19. @Override
  20. public void handleMessage(Message msg) {
  21. switch(msg.what)
  22. {
  23. case 0:
  24. Bundle date=msg.getData();
  25. txt.setText(String.valueOf(date.getInt("time")));

  26. Log.d("ThreadId", "HandlerMessage:"
  27. + String.valueOf(Thread.currentThread().getId()));
  28. Log.d("ThreadId", "msgDate:"
  29. + String.valueOf(date.getInt("time")));
  30. break;

  31. }

  32. }

  33. };

  34. btnStart.setOnClickListener(this);
  35. btnStop.setOnClickListener(this);
  36. }

  37. @Override
  38. public void onClick(View v) {
  39. switch (v.getId()) {
  40. case R.id.btnStartTime:
  41. //myHandler.post(this);
  42. myHandler.postDelayed(this, 1000);
  43. break;
  44. case R.id.btnStopTime:

  45. break;
  46. }

  47. }

  48. @Override
  49. public void run() {
  50. while(true)
  51. {
  52. total--;
  53. if(total<0)
  54. break;
  55. try {
  56. Thread.sleep(1000);
  57. } catch (InterruptedException e) {
  58. // TODO Auto-generated catch block
  59. e.printStackTrace();
  60. }
  61. Message msg=new Message();
  62. Bundle date = new Bundle();// 存放数据
  63. date.putInt("time", total);
  64. msg.setData(date);
  65. msg.what=0;
  66. Log.d("ThreadId", "POST:"
  67. + String.valueOf(Thread.currentThread().getId()));
  68. myHandler.sendMessage(msg);
  69. Log.d("ThreadId", "Thread:"
  70. + String.valueOf(Thread.currentThread().getId()));

  71. }

  72. }

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

  2. import java.util.Timer;

  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.os.Message;
  7. import android.util.Log;
  8. import android.view.View;
  9. import android.view.View.OnClickListener;
  10. import android.widget.Button;
  11. import android.widget.TextView;

  12. public class PostHandler extends Activity implements OnClickListener, Runnable {

  13. private TextView txt;
  14. private Button btnStart, btnStop;
  15. private Handler myHandler;
  16. private Timer timer;
  17. private int total = 60;
  18. private TimerThread timerThread;

  19. @Override
  20. protected void onCreate(Bundle savedInstanceState) {
  21. // TODO Auto-generated method stub
  22. super.onCreate(savedInstanceState);

  23. setContentView(R.layout.main);
  24. txt = (TextView) findViewById(R.id.txt);
  25. btnStart = (Button) findViewById(R.id.btnStartTime);
  26. btnStop = (Button) findViewById(R.id.btnStopTime);
  27. Log.d("ThreadId", "onCread:"
  28. + String.valueOf(Thread.currentThread().getId()));
  29. myHandler = new Handler()
  30. {

  31. @Override
  32. public void handleMessage(Message msg) {
  33. switch(msg.what)
  34. {
  35. case 0:
  36. Bundle date=msg.getData();
  37. txt.setText(String.valueOf(date.getInt("time")));

  38. Log.d("ThreadId", "HandlerMessage:"
  39. + String.valueOf(Thread.currentThread().getId()));
  40. Log.d("ThreadId", "msgDate:"
  41. + String.valueOf(date.getInt("time")));
  42. break;

  43. }

  44. }

  45. };

  46. btnStart.setOnClickListener(this);
  47. btnStop.setOnClickListener(this);
  48. }

  49. @Override
  50. public void onClick(View v) {
  51. switch (v.getId()) {
  52. case R.id.btnStartTime:
  53. //myHandler.post(this);
  54. //myHandler.postDelayed(this, 1000);
  55. timerThread=new TimerThread(myHandler,60);

  56. myHandler.post(timerThread);
  57. break;
  58. case R.id.btnStopTime:

  59. break;
  60. }

  61. }

  62. @Override
  63. public void run() {
  64. while(true)
  65. {
  66. total--;
  67. if(total<0)
  68. break;
  69. try {
  70. Thread.sleep(1000);
  71. } catch (InterruptedException e) {
  72. // TODO Auto-generated catch block
  73. e.printStackTrace();
  74. }
  75. Message msg=new Message();
  76. Bundle date = new Bundle();// 存放数据
  77. date.putInt("time", total);
  78. msg.setData(date);
  79. msg.what=0;
  80. Log.d("ThreadId", "POST:"
  81. + String.valueOf(Thread.currentThread().getId()));
  82. myHandler.sendMessage(msg);
  83. Log.d("ThreadId", "Thread:"
  84. + String.valueOf(Thread.currentThread().getId()));

  85. }

  86. }

  87. }
复制代码

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


文章原文http://www.eoeandroid.com/thread-116154-1-1.html

更多相关文章

  1. 子线程新建Handler为什么会报错?——浅谈Handler、Looper、Messag
  2. Android应用程序消息处理机制(Looper、Handler)分析
  3. Android消息处理系统——Looper、Handler、Thread
  4. 创建一个android的Splash Screen
  5. Android中Handler与Message的简单实例
  6. Android中几种图像特效处理的集锦!!
  7. Android(安卓)最火快速开发框架AndroidAnnotations简介
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. 2011.07.08——— android n获得壁纸
  2. Android(安卓)软键盘那点事
  3. android Theme
  4. Android获取打开各种文件Intent汇总
  5. android双击返回键退出程序
  6. Android浏览器如何打开网页
  7. 改变ScrollView的滚动条的颜色
  8. Android
  9. Android(安卓)使用URL通过浏览器调用andr
  10. android高手系列