Android总结Handler异步更新UI界面

本篇文章通过三种方式来实现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的源码。


好了,看到我们的效果图,三种方式实现的最终效果一致。

Android总结Handler异步更新UI界面_第1张图片


项目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循环加上线程睡眠不断创建新消息。缺点是不易于控制,本文通过标志进行控制。


好了,本篇文章就到此结束了。如果还有什么问题的话,可以在下面留言。大家共同讨论共同进步。谢谢阅读 !

你可能感兴趣的:(java,多线程,编程,android,异步)