Android总结Handler异步更新UI界面(转载)

转载地址: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 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/qq_22079023/article/details/85213136