如何使用AsyncTask-自訂執行器

如何使用AsyncTask-自訂執行器

如何使用AsyncTask-實作中實作了一個簡單的AsyncTask範例,
但是在如何使用AsyncTask中表示實作多個任務會讓共用的ThreadPool產生阻塞(blocking),
因此AsyncTask允許你自訂自己的執行器。

而我們知道AsyncTask執行有兩種形式,
在API 13以後, 預設是循序的,
實際上你也可以改用並行的。

//循序
executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, parameter);
//並行
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, parameter);

但是這樣一來仍然是使用公用的執行器, 仍然會阻塞問題,
因此要把兩個結合起來,
當你想循序, 可以自訂執行器為single。

executeOnExecutor(Executors.newSingleThreadExecutor(), parameter);

反之, 並行可以宣告多個Thread的ThreadPool。

executeOnExecutor(Executors.newCachedThreadPool(), parameter);

下面用如何使用AsyncTask-實作的例子來改寫。
使用兩個TextView, 跟一個Button,
當按下Button的時候, 並行兩個任務, 並且把結果顯示在TextView上面。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    <Button
        android:id="@+id/send_task"
        android:text="send task"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:layout_below="@id/send_task"
        android:id="@+id/message"
        android:text="Hello World!"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:layout_below="@id/message"
        android:id="@+id/message_2"
        android:text="Hello World!"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

接著都是相同方式,
只是多了一個index來判斷是第一個任務還是第二個任務,
目的來表示他真的是並發執行。

public class MainActivity extends AppCompatActivity {
    private Button sendTask;
    private TextView msg, msg2;
    private StringBuffer stringBuffer, stringBuffer2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
    }

    private void initData(){
        stringBuffer = new StringBuffer();
        stringBuffer2 = new StringBuffer();
    }

    private void initView(){
        sendTask = (Button) findViewById(R.id.send_task);
        msg = (TextView) findViewById(R.id.message);
        msg2 = (TextView) findViewById(R.id.message_2);
        sendTask.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getTask(1, "a", "b", "c", "d", "e");
                getTask(2, "f", "g", "h", "i", "j");
            }
        });
    }
    private AsyncTask<String, Integer, String[]> getTask(final int index, String... name){
        stringBuffer.delete(0, stringBuffer.length());
        stringBuffer2.delete(0, stringBuffer2.length());
        return new AsyncTask<String, Integer, String[]>() {
            private int count;
            @Override
            protected String[] doInBackground(String... params) {
                for(String s : params) {
                    try {
                        int rand = (int)(Math.random()*3 + 1);
                        Thread.sleep(rand * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    publishProgress(count, params.length);
                    count++;
                }
                return params;
            }

            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
                int percent = (int)(100 / values[1] * count);
                if(index == 1) {
                    msg.setText(percent + "%");
                } else{
                    msg2.setText(percent + "%");
                }
            }

            @Override
            protected void onPostExecute(String[] s) {
                super.onPostExecute(s);
                for(String str : s) {
                    if(index == 1) {
                        stringBuffer.append(str).append("\n");
                        msg.setText(stringBuffer);
                    } else{
                        stringBuffer2.append(str).append("\n");
                        msg2.setText(stringBuffer2);
                    }
                }
            }
        }.executeOnExecutor(Executors.newCachedThreadPool(), name);
    }

}

結果如下

程式碼