前言
學習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
public
void
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中用以和消息發送、處理時所做的線程進行比較。
實現Button按鈕的事件處理以此進入倒計時操做。這裏使用的Timer 來執行定時操做(其實咱們徹底能夠另起一個線程)。Task類繼承了TimerTask類,裏面增長了一個任務處理接口來實現回調模式,應此Activity須要實現該回調的接口 ITaskCallBack(這樣作是由於我比較不喜歡內部類的編寫方法)。
ICallBack接口和Task類
public
interface
ITaskCallBack {
void
TaskRun();
}
public
class
Task
extends
TimerTask {
private
ITaskCallBack iTask;
public
Task(ITaskCallBack iTaskCallBack)
{
super
();
iTask
=
iTaskCallBack;
}
public
void
setCallBack(ITaskCallBack iTaskCallBack)
{
iTask
=
iTaskCallBack;
}
@Override
public
void
run() {
//
TODO Auto-generated method stub
iTask.TaskRun();
}
}
這是Java的回調函數的通常寫法。
實現CallBack
/**
* 實現消息處理
*/
@Override
public
boolean
handleMessage(Message msg) {
switch
(msg.what)
{
case
0
:
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
;
}
return
false
;
}
運行結果
能夠看到在onCreate 方法中線程的ID是1(UI線程) 這與 HandlerMessage 進行消息處理時是所做的線程ID是同樣的,而消息發送的線程ID則爲8非UI線程。
使用Threadle進行實現
自定義的線程類
**
*
自定義的線程類,經過傳入的Handler,和Total 按期執行耗時操做
*
@author linzijun
*
*/
public
class
TimerThread
extends
Thread {
public
int
Total
=
60
;
public
Handler handler;
/**
* 初始化構造函數
*
@param
mhandler handler 用於發送消息
*
@param
total 總週期
*/
public
TimerThread(Handler mhandler,
int
total)
{
super
();
handler
=
mhandler;
Total
=
total;
}
@Override
public
void
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的方式 是將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;
public
class
PostHandler
extends
Activity
implements
OnClickListener, Runnable {
private
TextView txt;
private
Button btnStart, btnStop;
private
Handler myHandler;
private
Timer timer;
private
int
total
=
60
;
private
TimerThread timerThread;
@Override
protected
void
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
public
void
handleMessage(Message msg) {
switch
(msg.what)
{
case
0
:
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
public
void
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
public
void
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()));
}
}
}
請你們尊重原創,本人的轉帖主要是爲了我的學習