前言

  学习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

 

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

 

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

 

实现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

系列索引

  
Android 开源项目-StandupTimer学习笔记索引  
 
 
Handler的使用(一)

Handler基本概念:
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分逐个的在消息队列中将消息取出,然后对消息进行出来,就是发送消息和接收消息不是同步的处理。
这种机制通常用来处理相对耗时比较长的操作。

使用一个例子简单的来介绍一下Handler。
示例1:一个应用程序中有2个按钮(start、end),当点击start按钮时,执行一个线程,这个线程在控制台输出一串字符串,并且每隔3秒再执行一次线程,直到点击end按钮为止,线程停止。
下图为这个应用程序的界面:




下图为执行程序时控制台的输出:




开发步骤:
1、 新建一个Android应用程序
2、 在布局文件中添加2个Button控件标签,并为其设置属性和值
3、 在Activity中,声明控件变量并根据id获得控件对象
4、 在Activity中,创建一个Handler对象
5、 在Activity中,创建一个Runnable对象
a) 以匿名内部类的方式
b) 将要执行的操作写在Runnable对象中的run()方法中
i. 打印出一句话
ii. 调用Runnable对象的postDelayed()方法
6、 在Activity中,编写start按钮需要的监听器,并绑定
a) 在这个监听器的Onclick()方法中,调用Handler的post()方法,将要执行的线程对象放到队列当中。
7、 在Activity中,编写end按钮需要的监听器,并帮定
a) 在这个监听器的Onclick()方法中,调用Handler的removeCallbacks ()方法,删除队列当中未执行的线程对象。
b)
下面是Activity的代码:
Java代码 复制代码 收藏代码
  1. package android.handler;   
  2.   
  3. import android.app.Activity;   
  4. import android.os.Bundle;   
  5. import android.os.Handler;   
  6. import android.view.View;   
  7. import android.view.View.OnClickListener;   
  8. import android.widget.Button;   
  9.   
  10. public class HandlerTest extends Activity {   
  11.     /** Called when the activity is first created. */  
  12.     private Button startButton;   
  13.     private Button endButton;   
  14.        
  15.     @Override  
  16.     public void onCreate(Bundle savedInstanceState) {   
  17.         super.onCreate(savedInstanceState);   
  18.         setContentView(R.layout.main);   
  19.         //根据id获得控件对象   
  20.         startButton = (Button)findViewById(R.id.startButton);   
  21.         endButton = (Button)findViewById(R.id.endButton);   
  22.         //为控件设置监听器   
  23.         startButton.setOnClickListener(new StartButtonListener());   
  24.         endButton.setOnClickListener(new EndButtonListener());   
  25.     }   
  26.        
  27.     class StartButtonListener implements OnClickListener{   
  28.         public void onClick(View v) {   
  29.             //调用Handler的post()方法,将要执行的线程对象放到队列当中   
  30.             handler.post(updateThread);   
  31.         }   
  32.     }   
  33.        
  34.     class EndButtonListener implements OnClickListener{   
  35.         public void onClick(View v) {   
  36.             //调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象   
  37.             handler.removeCallbacks(updateThread);   
  38.         }   
  39.            
  40.     }   
  41.        
  42.     //创建Handler对象   
  43.     Handler handler = new Handler();   
  44.     //新建一个线程对象   
  45.     Runnable updateThread = new Runnable(){   
  46.         //将要执行的操作写在线程对象的run方法当中   
  47.         public void run(){   
  48.             System.out.println("updateThread");   
  49.             //调用Handler的postDelayed()方法   
  50.             //这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象   
  51.             //第一个参数是Runnable类型:将要执行的线程对象   
  52.             //第二个参数是long类型:延迟的时间,以毫秒为单位   
  53.             handler.postDelayed(updateThread, 3000);   
  54.         }   
  55.     };   
  56. }  
package android.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class HandlerTest extends Activity {
    /** Called when the activity is first created. */
	private Button startButton;
	private Button endButton;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //根据id获得控件对象
        startButton = (Button)findViewById(R.id.startButton);
        endButton = (Button)findViewById(R.id.endButton);
        //为控件设置监听器
        startButton.setOnClickListener(new StartButtonListener());
        endButton.setOnClickListener(new EndButtonListener());
    }
    
    class StartButtonListener implements OnClickListener{
		public void onClick(View v) {
			//调用Handler的post()方法,将要执行的线程对象放到队列当中
			handler.post(updateThread);
		}
    }
    
    class EndButtonListener implements OnClickListener{
		public void onClick(View v) {
			//调用Handler的removeCallbacks()方法,删除队列当中未执行的线程对象
			handler.removeCallbacks(updateThread);
		}
    	
    }
    
    //创建Handler对象
    Handler handler = new Handler();
    //新建一个线程对象
    Runnable updateThread = new Runnable(){
    	//将要执行的操作写在线程对象的run方法当中
    	public void run(){
    		System.out.println("updateThread");
    		//调用Handler的postDelayed()方法
    		//这个方法的作用是:将要执行的线程对象放入到队列当中,待时间结束后,运行制定的线程对象
    		//第一个参数是Runnable类型:将要执行的线程对象
    		//第二个参数是long类型:延迟的时间,以毫秒为单位
    		handler.postDelayed(updateThread, 3000);
    	}
    };
}

上面是一个最简单的例子,下面再看另外一个例子。
示例2:一个应用程序中有一个进度条和一个按钮,当点击按钮后,每隔一秒钟进度条前进一部分。
下图为应用程序的运行效果图:




开发步骤:
1、 新建一个Android应用程序
2、 在布局文件中添加一个progressBar和一个Button,并为其设置属性和值
3、 在Activity中,声明控件变量并根据id获得控件对象
4、 创建线程对象
a) 通过匿名内部类的方式
b) 在编写完了5、6步之后再来继续编写这个线程对象里的操作
i. 声明一个变量用来设置进度条的进度
ii. 重写线程类的run方法(),里面编写要执行的操作
1. 打印一个字符串
2. 进度条的值增加
3. 得到一个消息对象
4. 设置消息对象arg1的值
5. 让线程休眠一秒钟
6. 将消息对象放入到消息队列中
7. 判断,如果进度条的值等于100,则将线程对象从队列中移除。
5、 创建Handler对象
a) 与示例1不同的地方是,这里是通过匿名内部类的方式来声明的,而示例1是直接new出来的对象
b) 重写Handler对象的handlerMessage(Message msg)方法
i. 这个方法传入了一个Message对象,即消息对象,首先设置进度条的进度(这个值是Messag对象里面的一个成员变量arg1)。
ii. 将要执行的线程对象放入到队列当中
6、 编写Button需要的监听器,并绑定
a) 设置进度条为显示状态
b) 将要执行的线程对象放入到队列当中
下面是Activity的代码:
Java代码 复制代码 收藏代码
  1. package android.handler;   
  2.   
  3. import android.app.Activity;   
  4. import android.os.Bundle;   
  5. import android.os.Handler;   
  6. import android.os.Message;   
  7. import android.view.View;   
  8. import android.view.View.OnClickListener;   
  9. import android.widget.Button;   
  10. import android.widget.ProgressBar;   
  11.   
  12. public class ProgressBarHandlerTest extends Activity {   
  13.     /** Called when the activity is first created. */  
  14.        
  15.     private ProgressBar progressBar;   
  16.     private Button startButton;   
  17.        
  18.     @Override  
  19.     public void onCreate(Bundle savedInstanceState) {   
  20.         super.onCreate(savedInstanceState);   
  21.         setContentView(R.layout.main);   
  22.            
  23.         progressBar = (ProgressBar)findViewById(R.id.progressbar);   
  24.         startButton = (Button)findViewById(R.id.startButton);   
  25.            
  26.         startButton.setOnClickListener(new ProgressBarOnClickListener());   
  27.     }   
  28.        
  29.     class ProgressBarOnClickListener implements OnClickListener{   
  30.         public void onClick(View v) {   
  31.             //设置进度条为可见状态   
  32.             progressBar.setVisibility(View.VISIBLE);   
  33.             updateBarHandler.post(updateThread);   
  34.         }   
  35.     }   
  36.        
  37.     //使用匿名内部类来复写Handler当中的handlerMessage()方法   
  38.     Handler updateBarHandler = new Handler(){   
  39.         @Override  
  40.         public void handleMessage(Message msg) {   
  41.             progressBar.setProgress(msg.arg1);   
  42.             updateBarHandler.post(updateThread);    //将要执行的线程放入到队列当中   
  43.         }   
  44.     };   
  45.        
  46.     //线程类,该类使用匿名内部类的方式进行声明   
  47.     Runnable updateThread = new Runnable(){   
  48.         int i = 0;   
  49.         public void run() {   
  50.             // TODO Auto-generated method stub   
  51.             System.out.println("Begin Thread");   
  52.             i+=10;   
  53.             //得到一个消息对象,Message类是android系统提供的   
  54.             Message msg = updateBarHandler.obtainMessage();   
  55.             //将Message对象的arg1参数的值设置为i   
  56.             msg.arg1 = i;   //用arg1、arg2这两个成员变量传递消息,优点是系统性能消耗较少   
  57.             try{   
  58.                 Thread.sleep(1000); //让当前线程休眠1000毫秒   
  59.             }catch(InterruptedException ex){   
  60.                 ex.printStackTrace();   
  61.             }   
  62.             //将Message对象加入到消息队列当中   
  63.             updateBarHandler.sendMessage(msg);   
  64.             //如果i的值等于100   
  65.             if (i == 100){   
  66.                 //将线程对象从队列中移除   
  67.                 updateBarHandler.removeCallbacks(updateThread);    
  68.             }   
  69.         }   
  70.     };   
  71. }  
package android.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;

public class ProgressBarHandlerTest extends Activity {
    /** Called when the activity is first created. */
	
	private ProgressBar progressBar;
	private Button startButton;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        progressBar = (ProgressBar)findViewById(R.id.progressbar);
        startButton = (Button)findViewById(R.id.startButton);
        
        startButton.setOnClickListener(new ProgressBarOnClickListener());
    }
    
    class ProgressBarOnClickListener implements OnClickListener{
		public void onClick(View v) {
			//设置进度条为可见状态
			progressBar.setVisibility(View.VISIBLE);
			updateBarHandler.post(updateThread);
		}
    }
    
    //使用匿名内部类来复写Handler当中的handlerMessage()方法
    Handler updateBarHandler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			progressBar.setProgress(msg.arg1);
			updateBarHandler.post(updateThread);	//将要执行的线程放入到队列当中
		}
    };
    
    //线程类,该类使用匿名内部类的方式进行声明
    Runnable updateThread = new Runnable(){
    	int i = 0;
		public void run() {
			// TODO Auto-generated method stub
			System.out.println("Begin Thread");
			i+=10;
			//得到一个消息对象,Message类是android系统提供的
			Message msg = updateBarHandler.obtainMessage();
			//将Message对象的arg1参数的值设置为i
			msg.arg1 = i;	//用arg1、arg2这两个成员变量传递消息,优点是系统性能消耗较少
			try{
				Thread.sleep(1000);	//让当前线程休眠1000毫秒
			}catch(InterruptedException ex){
				ex.printStackTrace();
			}
			//将Message对象加入到消息队列当中
			updateBarHandler.sendMessage(msg);
			//如果i的值等于100
			if (i == 100){
				//将线程对象从队列中移除
				updateBarHandler.removeCallbacks(updateThread);	
			}
		}
    };
}

项目源码已经上传到附件了,有需要的可下载。

不知道大家有没有弄明白哈,我自己都写得晕晕乎乎的了,没办法啊语文写作能力不咋地,汗~



这里其实有一点我没有弄明白,就是当进度条的值等于100的时候,就将线程对象从队列中移除,从而停止线程的运行;这个在示例1中是没有问题的,当点击end按钮,线程停止;但是在示例2例子中,当进度条的值等于100了,可是却没有停止,还是在继续的运行,每隔一秒就执行一个线程,不知道这是为什么,研究了好一会儿都没弄明白,希望各位知道的可以跟我说说哈,咱们有机会多探讨探讨、多交流交流!
  • 大小: 41.2 KB
  • 大小: 20.1 KB
  • 大小: 126.5 KB
  • 大小: 39.2 KB
posted on 2012-06-14 16:06  清沁  阅读(823)  评论(1编辑  收藏  举报