本篇文章通过三种方式来实现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
接下来就是我们的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();//注销计时器事件
};
}
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对象
};
}
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循环加上线程睡眠不断创建新消息。缺点是不易于控制,本文通过标志进行控制。
好了,本篇文章就到此结束了。如果还有什么问题的话,可以在下面留言。大家共同讨论共同进步。谢谢阅读 !