zoukankan      html  css  js  c++  java
  • 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布局:
    Layout
    <?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"
    />
    <Button
    android:id="@+id/btnStartTime"
    android:text
    ="开始计时"
    android:layout_width
    ="80dip"
    android:layout_height
    ="wrap_content"

    ></Button>
    <Button
    android: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主要是用于查看线程是否被阻塞(阻塞时无法拖动)。
     
    onCreate
    @Override
    publicvoid 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中用以和消息发送、处理时所作的线程进行比较。
     
    发送消息

    @Override
    publicvoid 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继承自TimerTask
    Task 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();

    }

    @Override
    publicvoid 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;
    }
    @Override
    publicvoid run() {
    // TODO Auto-generated method stub
    iTask.TaskRun();
    }

    }
    这是Java的回调函数的一般写法。
     
    实现CallBack

    /**
    * 实现消息处理
    */
    @Override
    publicboolean 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. */
    @Override
    publicvoid 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);

    }

    /**
    * 实现消息处理
    */
    @Override
    publicboolean 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;
    }

    @Override
    publicvoid 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;
    }
    @Override
    publicvoid 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发送给消息队列,它将在到达时进行处理。
    POST

    publicclass PostHandler extends Activity implements OnClickListener, Runnable {

    private TextView txt;
    private Button btnStart, btnStop;
    private Handler myHandler;
    private Timer timer;
    privateint total =60;


    @Override
    protectedvoid 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()
    {

    @Override
    publicvoid 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);
    }

    @Override
    publicvoid onClick(View v) {
    switch (v.getId()) {
    case R.id.btnStartTime:
    //myHandler.post(this);
    myHandler.postDelayed(this, 1000);
    break;
    case R.id.btnStopTime:

    break;
    }

    }

    @Override
    publicvoid 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过去,运行结果是一样的。
    代码
    package zijunlin.me;

    import java.util.Timer;

    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;

    publicclass PostHandler extends Activity implements OnClickListener, Runnable {

    private TextView txt;
    private Button btnStart, btnStop;
    private Handler myHandler;
    private Timer timer;
    privateint total =60;
    private TimerThread timerThread;

    @Override
    protectedvoid 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()
    {

    @Override
    publicvoid 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);
    }

    @Override
    publicvoid onClick(View v) {
    switch (v.getId()) {
    case R.id.btnStartTime:
    //myHandler.post(this);
    //myHandler.postDelayed(this, 1000);
    timerThread=new TimerThread(myHandler,60);

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

    break;
    }

    }

    @Override
    publicvoid 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方法)”。

    参考文献

      SDK
  • 相关阅读:
    HDU 1010 Tempter of the Bone
    HDU 4421 Bit Magic(奇葩式解法)
    HDU 2614 Beat 深搜DFS
    HDU 1495 非常可乐 BFS 搜索
    Road to Cinema
    Sea Battle
    Interview with Oleg
    Spotlights
    Substring
    Dominating Patterns
  • 原文地址:https://www.cnblogs.com/keyindex/p/1822463.html
Copyright © 2011-2022 走看看