天天看點

Android中更新UI的三種方式

Android中更新UI的三種方式:

1.在工作線程中更新UI

2.使用AsyncTask

3.使用Handler

本部落格的界面用的同一個xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/hello_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <Button
        android:id="@+id/change_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Change"
        android:textAllCaps="false"/>

</LinearLayout>
           

1.在工作線程中更新

在上一篇部落格中,我寫到工作線程中不能對UI控件進行操作,但最後提到了(Android系統提供了一些工具用于在工作線程中更新主線程)

(1)使用View的postInvalidate()方法重新整理頁面

(2)使用Activity的runOnUiThread()方法更新UI

(3)使用View的post()和postDelayed()方法更新UI

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final TextView tv = (TextView) findViewById(R.id.hello_text);
        Button bt = (Button) findViewById(R.id.change_btn);

        final ExecutorService mThreadPool = Executors.newCachedThreadPool();
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mThreadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        //重新整理界面
//                        tv.postInvalidate();

                        //使用Activity的runOnUiThread()方法更新UI
//                        MainActivity.this.runOnUiThread(new Runnable() {
//                            @Override
//                            public void run() {
//                                tv.setText("OH,I am Fine!!!");
//                            }
//                        });

                        //使用View的post()方法更新UI
//                        tv.post(new Runnable() {
//                            @Override
//                            public void run() {
//                                tv.setText("Hi,Fresh By Post");
//                            }
//                        });

                        //使用View的postDelayed()方法更新UI
                        tv.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                tv.setText("Hi,Fresh By postDelayed :");
                            }
                        },1000);
                    }
                });
            }
        });
    }
}
           

2.使用AsyncTask

AsyncTask是Android給我們提供的一種輕量級的異步任務類

我們做一個點選按鈕後,demo會進行10s的倒計時

我們重寫了doInBackground()後,剩下5個回調方法,他們也是AsyncTask中的生命周期方法,我們在相應的方法中進行初始化,指派等操作。(下面的代碼中有詳細的備注)

Android中更新UI的三種方式

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt = (Button) findViewById(R.id.change_btn);

        final ExecutorService mThreadPool = Executors.newCachedThreadPool();
        bt.setOnClickListener(new View.OnClickListener() {
            MyAsyncTask myAsyncTask;
            @Override
            public void onClick(View v) {
                myAsyncTask = new MyAsyncTask();
                myAsyncTask.execute(Long.valueOf("10"));
            }
        });
    }

    class MyAsyncTask extends AsyncTask<Object,String,String>{

        TextView tv;

        @Override
        protected void onPreExecute() {
            tv = (TextView) findViewById(R.id.hello_text);

            tv.setText("倒計時開始!");
        }

        /**
         * doInBackground()方法是必須重寫的一個方法
         * 唯一的一個運作在工作線程中的方法
         * 用來執行在工作線程中要執行的任務
         */
        @SuppressLint("WrongThread")
        @Override
        protected String doInBackground(Object... objects) {
            if (objects.length == 1 && objects[0] instanceof Long){
                Long inputTime = (Long) objects[0];
                for (;inputTime > 0;inputTime--){
                    publishProgress(inputTime + "s"); //傳給onProgressUpdate()的參數
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }else{
                //這裡用到了上面的線程中更新UI的方法,不是AsyncTask更新UI的方法
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText("倒計時失敗");
                    }
                });
                cancel(true);
            }
            return null;
        }

        /**
         * onProgressUpdate()方法是運作在主線程中的方法
         * 是以我們在這裡可以直接對UI進行更新
         *
         * 我們下面擷取的values是上面publishProgress傳的參數
         * (本demo中隻有一個String類型的參數)
         */
        @Override
        protected void onProgressUpdate(String... values) {
            tv.setText(values[0]);
        }

        /**
         * onPostExecute()方法是doInBackground()方法執行完畢後執行的方法
         */
        @Override
        protected void onPostExecute(String s) {
            tv.setText("倒計時完畢");
        }

        /**
         * 取消時的回調方法
         */
        @Override
        protected void onCancelled(String s) {
            super.onCancelled(s);
        }
    }
}
           

效果截圖:

Android中更新UI的三種方式

3.使用Handler更新UI

Handler是Android消息機制的上層接口。Handler是專門用來線上程之間傳遞消息的工具類,主要用于UI界面的更新,消息的傳遞與處理。

Handler發送消息的兩種方法:

1.send系列方法:用于發送一個包含資料的Message對象,并在handleMessage(Message message)方法中處理。(下面demo使用的方法)

2.post系列的方法:用于發送一個Runnable對象,并在MessageQueue收到消息時執行。

public class MainActivity extends AppCompatActivity {

    private static final int CHANGE = 1;
    private TextView tv;

    private final MyHandle handle = new MyHandle();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt = (Button) findViewById(R.id.change_btn);
        tv = (TextView) findViewById(R.id.hello_text);

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message ms = new Message();
                        ms.what = CHANGE;
                        handle.sendMessage(ms);
                    }
                }).start();
            }
        });
    }

    class MyHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case CHANGE:
                    tv.setText("hello, Changed by Handle!!!");
                    break;
                default:
                    break;
            }
        }
    }
}