一般情況下,UI的更新都少不了Handler,首先我們先了解一下Handler機制:
Handler消息機制
定義
Message
線程間通信的數據單元,可通過message攜帶需要的數據創建對象:Message.obtain(what)
Handler
Handler是Message的處理器,同時也負責消息的發送和移除工作
發送即時消息:即使發送即時處理
發送延時消息:即時發送,過一會兒處理
MessageQueue:消息隊列
用來存放通過Handler發送的消息,它是一個按Message的when排序的優先級隊列
Looper:循環器
負責循環取出Message Queue里面的當前需要處理的Message,交給對應的Handler進行處理,處理完后,將Message緩存到消息池中,以備復用
Handler的基本使用
步驟:
①創建Handler成員變量,並重寫其handleMessage()
②在分線程創建Message對象
③使用handler對象發送Message
④在handleMessage()中處理消息
消息機制原理
文字描述
從handler中獲取一個消息對象,把數據封裝到消息對象中,通過handler的send方法把消息push到MessageQueue隊列中,looper對象會輪詢MessageQueue隊列,把消息對象取出。通過dispatchMessage分發給Handler,再回調用Handler實現的handleMessage方法處理消息。
這里只是大致地描述了Handler消息機制的流程,你也可以跟着這位的文章讀下源碼https://blog.csdn.net/yanzhenjie1003/article/details/89218745
接下來,我們再看在通過子線程更新UI常見的幾種方式
通過子線程更新UI
首先我們要理解子線程可不可以更新UI,谷歌官方的說法是:一定要在主線程更新UI。
這是為什么?
如果多個線程更新UI,很容易造成整個界面的UI出錯。
那為什么又有通過子線程更新UI這種說法呢?
當我們需要進行耗時操作時(如聯網等),如果放在主線程,會對整個應用造成極大的負擔,用戶體驗極差,所以我們就通過Handler機制新開辟一個線程,耗時操作交給子線程,UI的更新實際還是主線程來實現的。
所以嚴謹來說是通過子線程更新UI,而不是子線程更新UI。
通過子線程更新UI
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button update_handler;
private Button update_ViewPost;
private Button update_handlerPost;
private Button update_handlerPostDelay;
private Button update_RunOnUiThread;
private Button update_AsyncTask;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
update_handler=findViewById(R.id.button1);
update_ViewPost=findViewById(R.id.button2);
update_handlerPost=findViewById(R.id.button3);
update_handlerPostDelay=findViewById(R.id.button4);
update_RunOnUiThread=findViewById(R.id.button5);
update_AsyncTask=findViewById(R.id.button6);
textView=findViewById(R.id.myword);
update_handler.setOnClickListener(this);
update_ViewPost.setOnClickListener(this);
update_handlerPost.setOnClickListener(this);
update_handlerPostDelay.setOnClickListener(this);
update_RunOnUiThread.setOnClickListener(this);
update_AsyncTask.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button1:
update_handler();
break;
case R.id.button2:
update_ViewPost();
break;
case R.id.button3:
update_handlerPost();
break;
case R.id.button4:
update_handlerPostDelay();
break;
case R.id.button5:
update_RunOnUiThread();
break;
case R.id.button6:
new updateAsyncTask().execute();
break;
}
}
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1){
textView.setText("小慕慕");
}
}
};
/*
方法1
*/
private void update_handler(){
new Thread(new Runnable() {
@Override
public void run() {
Message message=handler.obtainMessage();
message.what=1;
handler.sendMessage(message);
}
}).start();
}
/*
方法2
*/
private void update_ViewPost(){
new Thread(new Runnable() {
@Override
public void run() {
textView.post(new Runnable() {
@Override
public void run() {
textView.setText("小九九");
}
});
}
}).start();
}
/*
方法3
*/
private void update_handlerPost() {
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
textView.setText("小酒酒");
}
});
}
}).start();
}
/*
方法4
*/
private void update_handlerPostDelay(){
new Thread(new Runnable() {
@Override
public void run() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
textView.setText("九酒");
}
},3000);
}
}).start();
}
/*
方法5
*/
private void update_RunOnUiThread(){
new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("慕九");
}
});
}
}).start();
}
/*
方法6
*/
class updateAsyncTask extends AsyncTask<String,Integer,String>{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... strings) {
publishProgress();
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
textView.setText("結束");
}
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="handler"
android:textAllCaps="false"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="View.post()"
android:textAllCaps="false"
/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="handlerPost()"
android:textAllCaps="false"/>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="handlerPostDelay()"
android:textAllCaps="false"/>
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="runOnUiThread()"
android:textAllCaps="false"/>
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text=" update_AsyncTask()"
android:textAllCaps="false"/>
<TextView
android:id="@+id/myword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="慕九酒"/>
</LinearLayout>
運行結果:
總結
其實這六種方式並沒有太大的區別,前五種方式都是基於第一種方式的封裝,都是采用的Thread+handler模式,第六種封裝的更厲害了些,它是Thread+hanler+Threadpool。上面的代碼示例中有些看起來完全是在子線程更新的UI,實際上這是因為做的封裝讓我們看着好像是在子線程更新UI似的,實際上如果我們查看源碼,就會發現它還是通過handler機制在主線程更新的UI.