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

来源:互联网 发布:红包软件代理招募 编辑:程序博客网 时间:2024/05/17 04:42

引入


所有的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 0