引入
所有的Android应用程序都运行在一个独立的dalvik虚拟机中,dalvik虚拟机就是一个开辟在Linux内核中的一个进程,而每一个dalvik虚拟机启动的时候,都会启动一个主线程(MainThread),主线程主要负责处理UI相关的事件,所以MainThread又叫UI线程,这也是我题目的缘由。
在Android中,我们不能直接在子线程中更新UI,因为UI是单线程模式,我们只能在UI线程中对UI元素进行更改,要是直接对UI操作,就会报错。
同时,把一些耗时的代码放到非UI线程中执行,也能提高用户体验,还能避免UI更新5秒超时的ANR;
下面用实例来介绍一下Android中异步机制更新UI线程,用各种方法来更新一个TextView中的内容。
Android中异步更新UI的几种方法
- 使用 Activity.runOnUiThread(Runnable)方法
- 使用View.post(Runnable)或View.postDelayed(Runnable, long)方法
- 使用Handler的post(Runnable)或者postDelayed(Runnable, long)方法
- 使用Handler的消息传递机制
- 使用AsyncTask异步机制
0、多线程实现方法
- 继承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