id="@+id/SeekBar01"android:
layout_width="match_parent"android:
layout_height="wrap_content">
这里使用TextView来显示倒计时的时间变化,两个按钮用于控制时间的开始和停止。
SeekBar主要是用于查看线程是否被阻塞(阻塞时无法拖动)。
onCreate
@Override
publicvoidonCreate(BundlesavedInstanceState){
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=newHandler(this);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
}
在onCreate方法中初始化元素个元素,myHandler=newHandler(this);调用的是 Handler(Handler.Callback callback)构造函数,在回调方法callback中对发送来的消息进行处理(这样我们就不必使用内部类的写法来重写HandleMessage()方法了),因此Activity必须实现 android.os.Handler.Callback 接口。
我们还在将onCreate方法的ThreadId记录在了Log中用以和消息发送、处理时所作的线程进行比较。
发送消息
@Override
publicvoidonClick(Viewv){
switch(v.getId()){
caseR.id.btnStartTime:
startTimer();
break;
caseR.id.btnStopTime:
timer.cancel();
break;
}
}
privatesynchronizedvoidstartTimer(){
timer=newTimer();
//TimerTaskupdateTimerValuesTask=newTimerTask(){
//@Override
//publicvoidrun(){
//updateTimerValues();
//}
//
//};
//自定义的CallBack模式。
Task继承自TimerTask
TaskupdateTimerValuesTask=newTask(this);
timer.schedule(updateTimerValuesTask,1000,1000);
}
//执行耗时的倒计时任务。
privatevoidupdateTimerValues(){
total--;
Log.d("ThreadId","send:
"
+String.valueOf(Thread.currentThread().getId()));
Messagemsg=newMessage();
Bundledate=newBundle();//存放数据
date.putInt("time",total);
msg.setData(date);
msg.what=0;
myHandler.sendMessage(msg);
//另一种写法
//Messagemsg=myHandler.obtainMessage();
//Bundledate=newBundle();//存放数据
//date.putInt("time",total);
//msg.setData(date);
//msg.what=0;
//msg.sendToTarget();
}
@Override
publicvoidTaskRun(){
updateTimerValues();
}
实现Button按钮的事件处理以此进入倒计时操作。
这里使用的Timer来执行定时操作(其实我们完全可以另起一个线程)。
Task类继承了TimerTask类,里面增加了一个任务处理接口来实现回调模式,应此Activity需要实现该回调的接口 ITaskCallBack(这样做是因为我比较不喜欢内部类的编写方法)。
ICallBack接口和Task类
publicinterfaceITaskCallBack{
voidTaskRun();
}
publicclassTaskextendsTimerTask{
privateITaskCallBackiTask;
publicTask(ITaskCallBackiTaskCallBack)
{
super();
iTask=iTaskCallBack;
}
publicvoidsetCallBack(ITaskCallBackiTaskCallBack)
{
iTask=iTaskCallBack;
}
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
iTask.TaskRun();
}
}
这是Java的回调函数的一般写法。
实现CallBack
/**
*实现消息处理
*/
@Override
publicbooleanhandleMessage(Messagemsg){
switch(msg.what)
{
case0:
Bundledate=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类
publicclassThreadHandlerrActivityextendsActivityimplementsCallback,
OnClickListener{
privateTextViewtxt;
privateButtonbtnStart,btnStop;
privateHandlermyHandler;
privateTimerThreadtimerThread;
privateintTotal=30;
/**Calledwhentheactivityisfirstcreated.*/
@Override
publicvoidonCreate(BundlesavedInstanceState){
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=newHandler(this);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
}
/**
*实现消息处理
*/
@Override
publicbooleanhandleMessage(Messagemsg){
switch(msg.what)
{
case0:
Bundledate=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
publicvoidonClick(Viewv){
switch(v.getId()){
caseR.id.btnStartTime:
//自定义的线程
timerThread=newTimerThread(myHandler,60);
timerThread.start();
break;
caseR.id.btnStopTime:
timerThread.stop();
//timerThread.destroy();
break;
}
}
}
自定义的线程类
**
*自定义的线程类,通过传入的Handler,和Total定期执行耗时操作
*@authorlinzijun
*
*/
publicclassTimerThreadextendsThread{
publicintTotal=60;
publicHandlerhandler;
/**
*初始化构造函数
*@parammhandlerhandler用于发送消息
*@paramtotal总周期
*/
publicTimerThread(Handlermhandler,inttotal)
{
super();
handler=mhandler;
Total=total;
}
@Override
publicvoidrun(){
while(true)
{
Total--;
if(Total<0)
break;
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
Messagemsg=newMessage();
Bundledate=newBundle();//存放数据
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
publicclassPostHandlerextendsActivityimplementsOnClickListener,Runnable{
privateTextViewtxt;
privateButtonbtnStart,btnStop;
privateHandlermyHandler;
privateTimertimer;
privateinttotal=60;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
//TODOAuto-generatedmethodstub
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=newHandler()
{
@Override
publicvoidhandleMessage(Messagemsg){
switch(msg.what)
{
case0:
Bundledate=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
publicvoidonClick(Viewv){
switch(v.getId()){
caseR.id.btnStartTime:
//myHandler.post(this);
myHandler.postDelayed(this,1000);
break;
caseR.id.btnStopTime:
break;
}
}
@Override
publicvoidrun(){
while(true)
{
total--;
if(total<0)
break;
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
Messagemsg=newMessage();
Bundledate=newBundle();//存放数据
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过去,运行结果是一样的。
代码
packagezijunlin.me;
importjava.util.Timer;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.util.Log;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.TextView;
publicclassPostHandlerextendsActivityimplementsOnClick