轉載地址:https://blog.csdn.net/qq_21004057/article/details/51582412
本篇文章通過三種方式來實現UI控件的更新,Handler異步更新UI在安卓開發中最常用也非常實在。這篇文章注重實現思路,所以我就不在界面方面進行美化了,都是最原始的控件。有需要的可以收藏下,。雖說搜索引擎上關於Handler消息機制的文章已經數不盡數了,但是我寫這篇文章也是希望在開發中能幫助自己記憶起Handler的用法。
學會使用Handler來更新UI,由於在主線程中直接更新UI會阻塞線程,造成假死現象,所以我們通常採用Handler消息機制在UI線程中來更新UI控件。至於Handler消息機制,在這裏簡單介紹一下。本來還打算寫一種的,這裏就不詳細說了,通過在子線程使用Bundle封裝屬性到Message數據中,其次在Handler中解封裝得到Message數據再顯示到控件中。其原理與方法三無太大差別。
Handler消息機制原理簡介:通過Handler對象向消息隊列中Message Queue中發送消息Message,通過Looper對象來管理Queue中的Message。具體的大家可以查看Handler的源碼。
好了,看到我們的效果圖,三種方式實現的最終效果一致。
項目UI界面實現:3個Button,1個EditText,1個TextView。
項目實現原理:Handler機制實現UI更新。
項目邏輯實現:通過點擊按鈕獲取輸入框的時間並顯示在一個TextView上,然後通過點擊開始計時按鈕開始倒計時,可以通過停止計時按鈕停止計時。
實現方式一:Handler+Timer+TimerTask
通過該方式也是比較實用的,顧名思義,TimerTask計時器任務。由於Timer和TimerTask是同時出現的,TimerTask實現了Runnable接口,並且要求實現run方法。
首先,我們先編寫我們的佈局文件activity_main.xml,三種實現方式統一使用了該佈局。
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/inputTime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:hint="@null"/>
<Button
android:id="@+id/ensureTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="點擊" />
<TextView
android:id="@+id/showTime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/startTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="開始計時" />
<Button
android:id="@+id/stopTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止計時" />
</LinearLayout>
接下來就是我們的Activity實現步驟了。三種方式實現代碼如下:
MainActivity.java
package com.mero.countTime;
import java.util.Timer;
import java.util.TimerTask;
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.EditText;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
private EditText inputTime;
private TextView showTime;
private Button ensureTime,startTime,stopTime;
private Timer timer = null;
private TimerTask task = null;
private int i;//顯示的倒計時數字
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//實例化控件
}
/**實例化控件方法*/
private void initView() {
inputTime = (EditText) findViewById(R.id.inputTime);
showTime = (TextView) findViewById(R.id.showTime);
ensureTime = (Button) findViewById(R.id.ensureTime);
startTime = (Button) findViewById(R.id.startTime);
stopTime = (Button) findViewById(R.id.stopTime);
/**註冊監聽事件*/
ensureTime.setOnClickListener(this);
startTime.setOnClickListener(this);
stopTime.setOnClickListener(this);
};
@Override
public void onClick(View v) {
switch (v.getId()) {
/**當選擇點擊按鈕的監聽事件*/
case R.id.ensureTime:
showTime.setText(inputTime.getText().toString());
i=Integer.parseInt(inputTime.getText().toString());
break;
/**當選擇開始計時按鈕的監聽事件*/
case R.id.startTime:
startTime();
break;
case R.id.stopTime:
stopTime();
break;
}
}
/**當選擇停止計時按鈕的監聽事件*/
private Handler handler=new Handler(){
/**重寫handleMessage方法*/
@Override
public void handleMessage(Message msg) {
showTime.setText(msg.arg1+"");
startTime();//執行計時方法
}
};
/**開始計時方法*/
private void startTime(){
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
i--;
Message message = handler.obtainMessage();//獲取Message對象
message.arg1 = i;//設置Message對象附帶的參數
handler.sendMessage(message);//向主線程發送消息
}
};
timer.schedule(task, 1000);//執行計時器事件
};
/**停止計時方法*/
private void stopTime(){
timer.cancel();//註銷計時器事件
};
}
實現方式二:Handler+postDelayed+post
MainActivity.java
package com.mero.countTime;
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;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
private EditText inputTime;//聲明輸入框
private TextView showTime;//聲明用於顯示當前計時的時間
private Button ensureTime,startTime,stopTime;//聲明計時按鈕,停止計時按鈕和點擊按鈕
private int i;//顯示的倒計時數字
private Runnable update;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//實例化控件
}
/**實例化控件方法*/
private void initView() {
inputTime = (EditText) findViewById(R.id.inputTime);
showTime = (TextView) findViewById(R.id.showTime);
ensureTime = (Button) findViewById(R.id.ensureTime);
startTime = (Button) findViewById(R.id.startTime);
stopTime = (Button) findViewById(R.id.stopTime);
/**註冊監聽事件*/
ensureTime.setOnClickListener(this);
startTime.setOnClickListener(this);
stopTime.setOnClickListener(this);
};
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ensureTime:
showTime.setText(inputTime.getText().toString());//獲取輸入框上的時間並設置到顯示文本控件上
i=Integer.parseInt(inputTime.getText().toString());
break;
case R.id.startTime:
startTime();//開始計時
handler.post(update);
break;
case R.id.stopTime:
stopTime();//停止計時
break;
}
}
final Handler handler=new Handler();
/**開始計時方法*/
private void startTime(){
update=new Runnable(){
@Override
public void run() {
i--;
showTime.setText(i+"");
handler.postDelayed(update, 1000);//每隔1s將線程提交到線程隊列中
}
};
}
/**停止計時方法*/
private void stopTime(){
handler.removeCallbacks(update);//移除Runnable對象
};
}
實現方式三:Handler+Thread
MainActivity.java
package com.mero.countTime;
import android.annotation.SuppressLint;
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.EditText;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
private EditText inputTime;
private TextView showTime;
private Button ensureTime,startTime,stopTime;
private int i;//顯示的倒計時數字
private boolean flag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//實例化控件
}
private void initView() {
inputTime = (EditText) findViewById(R.id.inputTime);
showTime = (TextView) findViewById(R.id.showTime);
ensureTime = (Button) findViewById(R.id.ensureTime);
startTime = (Button) findViewById(R.id.startTime);
stopTime = (Button) findViewById(R.id.stopTime);
/**註冊監聽事件*/
ensureTime.setOnClickListener(this);
startTime.setOnClickListener(this);
stopTime.setOnClickListener(this);
};
@Override
public void onClick(View v) {
switch (v.getId()) {
/**點擊按鈕事件監聽*/
case R.id.ensureTime:
showTime.setText(inputTime.getText().toString());
i=Integer.parseInt(inputTime.getText().toString());
break;
/**開始按鈕事件監聽*/
case R.id.startTime:
flag=true;
startTime();
break;
/**停止按鈕事件監聽*/
case R.id.stopTime:
stopTime();
break;
}
}
final Handler handler=new Handler(){
public void handleMessage(Message msg) {
int p=msg.what;
showTime.setText(p+"");
};
};
/**開始計時方法*/
private void startTime() {
/**開啓一個新線程*/
new Thread(){
public void run() {
/**每睡眠1秒後發送Message給Handler處理*/
for(int j=i;j>=0;j--){
if(flag==true){
try {
Thread.sleep(1000);
Message msg=new Message();
msg.what=j;//設置Message附帶的參數
handler.sendMessage(msg);//發送Message對象給Handler
i=j;//將當前的時間傳遞給全局時間變量
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}.start();
}
/**停止計時方法,通過設置boolean標誌爲false來停止*/
@SuppressLint("NewApi")
private void stopTime(){
flag=false;
};
}
通過上面的代碼,我們來總結一下。
方法一:簡單實用,尤其定時刷新控件,效果非常good,使用簡單。注意Timer和TimerTask必須同時使用。使用Timer的schedule(task,delayed)方法提交TimerTask線程消息。由Handler處理線程消息。通過Timer.cancel(task)方式進行移除線程任務。
方法二:同方式一,簡單實用,原理實質一致。通過實例化Runnable對象來構造實現run創建新線程,在新線程中不斷將線程加入Looper池中進行處理。在主線程中通過post提交線程進行處理。通過handler.removeCallbacks(runnable)方式移除線程任務。
方法三:很經典實用的一種方式。通過for循環加上線程睡眠不斷創建新消息。缺點是不易於控制,本文通過標誌進行控制。
好了,本篇文章就到此結束了。如果還有什麼問題的話,可以在下面留言。大家共同討論共同進步。謝謝閱讀 !
---------------------
作者:Mero技術博客
來源:CSDN
原文:https://blog.csdn.net/qq_21004057/article/details/51582412
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!