Android异步机制更新UI线程(详解)

引入


所有的Android应用程序都运行在一个独立的dalvik虚拟机中,dalvik虚拟机就是一个开辟在Linux内核中的一个进程,而每一个dalvik虚拟机启动的时候,都会启动一个主线程(MainThread),主线程主要负责处理UI相关的事件,所以MainThread又叫UI线程,这也是我题目的缘由。
在Android中,我们不能直接在子线程中更新UI,因为UI是单线程模式,我们只能在UI线程中对UI元素进行更改,要是直接对UI操作,就会报错。
这里写图片描述

同时,把一些耗时的代码放到非UI线程中执行,也能提高用户体验,还能避免UI更新5秒超时的ANR;
下面用实例来介绍一下Android中异步机制更新UI线程,用各种方法来更新一个TextView中的内容。

Android中异步更新UI的几种方法

  1. 使用 Activity.runOnUiThread(Runnable)方法
  2. 使用View.post(Runnable)或View.postDelayed(Runnable, long)方法
  3. 使用Handler的post(Runnable)或者postDelayed(Runnable, long)方法
  4. 使用Handler的消息传递机制
  5. 使用AsyncTask异步机制

0、多线程实现方法

  1. 继承Thread类
class MyThread extends Thread{
    public Handler mHandler;
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        mHandler.sendEmptyMessage(0);
    }
}

调用的时候:

new MyThread().start();

2.实现Runnable接口

class MyRunnable implements Runnable{
    public Handler mHandler;
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mHandler.sendEmptyMessage(0);
    }

}

调用的时候:

new Thread(new MyRunnable()).start();

1、使用 Activity.runOnUiThread(Runnable)方法

核心代码模块:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        //使用使用runOnUiThread(Runnable)方法更新UI线程
        new MRunOnUiThread().start();

    }

    //内部类实现第一种更新UI的方法
    class MRunOnUiThread extends Thread{
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //延迟一秒
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mTextView.setText("使用runOnUiThread(Runnable)方法");
                }
            });
        }
    }

2、使用View.post(Runnable)或View.postDelayed(Runnable, long)方法

核心代码模块:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        //使用View.post(Runnable)或View.postDelayed(Runnable, long)方法
        new MViewPost().start();
    }

    //内部类实现第二种更新UI的方法
    class MViewPost extends Thread{
        @Override
        public void run() {
            mTextView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mTextView.setText("使用View.post(Runnable)或View.postDelayed(Runnable, long)方法");
                }
            },1000);
            /**下面post方法和上面的postDelayed方法效果是一样的,后者提供了一个延时参数而已**/
//            mTextView.post(new Runnable() {
//                @Override
//                public void run() {
//                    try {
//                        Thread.sleep(1000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    mTextView.setText("使用View.post(Runnable)或View.postDelayed(Runnable,     long)方法");
//                }
//            });
        }
    }

3、使用Handler的post(Runnable)或者postDelayed(Runnable,long)方法

核心代码模块:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        //使用Handler的post(Runnable)方法
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mTextView.setText("使用Handler的post(Runnable)" +
                        "或postDelayed(Runnable, long)方法");
            }
        },1000);
    }

4、使用Handler的消息传递机制

核心代码模块:

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 0x123){
                mTextView.setText("使用Handler的消息传递机制");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        //使用Handler的消息传递机制
        new MHandler().start();

    }
    //内部类实现第四种更新UI的方法
    class MHandler extends Thread{
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler.sendEmptyMessage(0x123);
        }
    }

5、使用AsyncTask异步机制

核心代码模块:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        //使用Handler的消息传递机制
        //new MHandler().start();
        //使用AsyncTask异步机制
        new MAsyncTask().execute();

    }
    //内部类实现第五种更新UI的方法
    class MAsyncTask extends AsyncTask<String,String,String>{
        @Override
        protected String doInBackground(String... params) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            mTextView.setText("使用AsyncTask异步机制");
        }
    }

6、总结一下

事实上,更新UI线程,还有很多的已经被封装开源框架,如Okhttp,Volley等,在项目中使用,能更有效率也能一定程度上提高性能。

UI线程更新是我们在开发过程中经常遇到的,熟练掌握各种更新方法,根据项目需求选用合适的方法。个人比较推荐Handler消息传递机制和AsyncTask异步机制更新UI线程,毕竟Handler的消息传递机制就是为了解决异步更新问题,AsyncTask类更是Google专门为了更新UI线程而提供的。

7、附录:源代码

效果展示:请忽略标题栏,顺手在旧的工程中撸的
这里写图片描述

源代码:

import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView mTextView;
    private Button btn_one;
    private Button btn_two;
    private Button btn_three;
    private Button btn_four;
    private Button btn_five;

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 0x123){
                mTextView.setText("使用Handler的消息传递机制");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    private void init() {
        mTextView = (TextView)findViewById(R.id.textView);
        btn_one = (Button)findViewById(R.id.btn_one);
        btn_two = (Button)findViewById(R.id.btn_two);
        btn_three = (Button)findViewById(R.id.btn_three);
        btn_four = (Button)findViewById(R.id.btn_four);
        btn_five = (Button)findViewById(R.id.btn_five);

        btn_one.setOnClickListener(this);
        btn_two.setOnClickListener(this);
        btn_three.setOnClickListener(this);
        btn_four.setOnClickListener(this);
        btn_five.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_one:
                //使用使用runOnUiThread(Runnable)方法更新UI线程
                new MRunOnUiThread().start();
                break;
            case R.id.btn_two:
                //使用View.post(Runnable)或View.postDelayed(Runnable, long)方法
                new MViewPost().start();
                break;
            case R.id.btn_three:
                //使用Handler的post(Runnable)方法
                Handler handlerPost = new Handler();
                handlerPost.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mTextView.setText("使用Handler的post(Runnable)" +
                                "或postDelayed(Runnable, long)方法");
                    }
                },1000);
                break;
            case R.id.btn_four:
                //使用Handler的消息传递机制
                new MHandler().start();
                break;
            case R.id.btn_five:
                //使用AsyncTask异步机制
                new MAsyncTask().execute();
                break;
        }
    }

    //内部类实现第五种更新UI的方法
    class MAsyncTask extends AsyncTask<String,String,String>{
        @Override
        protected String doInBackground(String... params) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(String s) {
            mTextView.setText("使用AsyncTask异步机制");
        }
    }
    //内部类实现第四种更新UI的方法
    class MHandler extends Thread{
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler.sendEmptyMessage(0x123);
        }
    }
    //内部类实现第二种更新UI的方法
    class MViewPost extends Thread{
        @Override
        public void run() {
            mTextView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mTextView.setText("使用View.post(Runnable)" +
                            "或View.postDelayed(Runnable, long)方法");
                }
            },1000);
            /**下面post方法和上面的postDelayed方法效果是一样的,后者提供了一个延时参数而已**/
            mTextView.post(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mTextView.setText("使用View.post(Runnable)" +
                            "或View.postDelayed(Runnable, long)方法");
                }
            });
        }
    }
    //内部类实现第一种更新UI的方法
    class MRunOnUiThread extends Thread{
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //延迟一秒
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mTextView.setText("使用runOnUiThread(Runnable)方法");
                }
            });
        }
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.jiaohanhan.intentdemo.MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="20sp"
        android:hint="未更新UI线程之前"
        />

    <Button
        android:layout_marginTop="40dp"
        android:layout_marginBottom="3dp"
        android:id="@+id/btn_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第一种方式更新UI线程"/>

    <Button
        android:layout_margin="3dp"
        android:id="@+id/btn_two"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第二种方式更新UI线程"/>

    <Button
        android:layout_margin="3dp"
        android:id="@+id/btn_three"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第三种方式更新UI线程"/>

    <Button
        android:layout_margin="3dp"
        android:id="@+id/btn_four"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第四种方式更新UI线程"/>

    <Button
        android:layout_margin="3dp"
        android:id="@+id/btn_five"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="第五种方式更新UI线程"/>
</LinearLayout>

参考文档
1、http://blog.csdn.net/mylzc/article/details/6736988
2、郭霖《第一行代码》(第二版)
3、https://segmentfault.com/a/1190000003702775
4、https://developer.android.com/reference/android/os/AsyncTask.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值