前言

  学习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( Looperlooper)、 Handler( Looperlooper, Handler.Callbackcallback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。

倒计时程序

  利用Timer 编写一个倒计时程序,程序使用Timer和TimerTask来完成倒计时,同时使用sendMessages方法发送消息,然后在HanleMessage里更新UI。 Activity布局: View Code
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主要是用于查看线程是否被阻塞(阻塞时无法拖动)。 View Code
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.Callbackcallback)构造函数,在回调方法callback中对发送来的消息进行处理(这样我们就不必使用内部类的写法来 重写HandleMessage()方法了),因此Activity必须实现 android.os.Handler.Callback接口。我们还在将onCreate 方法的ThreadId 记录在了Log中用以和消息发送、处理时所作的线程进行比较。 View Code
发送消息    @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(这样做是因为我比较不喜欢内部类的编写方法)。 View Code
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的回调函数的一般写法。 View Code
实现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进行实现

View Code View Code
自定义的线程类** * 自定义的线程类,通过传入的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发送给消息队列,它将在到达时进行处理。 View Code
POSTpublicclass 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 stubsuper.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过去,运行结果是一样的。 View Code
代码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 stubsuper.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方法)”。

参考文献

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

系列索引

   Android 开源项目-StandupTimer学习笔记索引 REFRENCES:http://www.cnblogs.com/keyindex/articles/1822463.html

更多相关文章

  1. Handler机制情景分析
  2. Android—android与js交互以及相互传参
  3. Android中R.java没有自动生成解决方案
  4. Android(安卓)Service 服务详细讲解
  5. android 处理运行时改变 开发文档翻译
  6. 详解 Android(安卓)的 Activity 组件
  7. Android(安卓)事件分发机制源码
  8. Android消息机制浅析——面试总结
  9. android spinner默认样式不支持换行和修改字体样式 的解决方法

随机推荐

  1. android按钮监听器的写法
  2. android 数据双向绑定学习笔记
  3. Android(安卓)-- 文件扫描
  4. Android SQLite详解及示例代码
  5. 2014.08.05 ——— android Gson JsonDes
  6. python系列学习六——移动开发
  7. SlidingMenu 在Android Studio使用详解
  8. Android(安卓)WebView 中遇到的问题集锦
  9. Android 布局文件属性讲解
  10. android采用pull解析器解析和生成XML