show code block

2017年11月26日 星期日

Android元件(AsyncTask)— 非同步任務、異步任務

前言

現在下載東西大多都使用第三方套件,異步任務都已經幫你處理得妥妥的。
但如果你要生成一張很大的圖片或是很好資源的任何東西,你就會需要它

這邊貼個介紹
http://aiur3908.blogspot.tw/2015/06/android-asynctask.html
超好懂的AsyncTask

以下簡略轉貼
求詳細請點上面網址

今日實作


重點程式碼

AsyncTask<Params, Progress, Result>



你開的class 會需要繼承 AsyncTask

而後面的三個參數

Params  代表著你要放入的參數,像是String 或是 int 

Progress 如果你要下載東西,這邊專門給你用進度條的參數

Result 就是你希望這條你新分出去的執行緒要回到主執行緒的時候要返回什麼東西。
如果你是拿來下載圖片,就可以返回Bitma。如果你是跑一個陣列,也可以返回ArrayList<>之類的....


而繼承AsyncTask會產生四個方法

onPreExecute  執行前,一些基本設定可以在這邊做。

doInBackground  執行中,在背景做任務。這邊就是重點中的重點,你希望下載或做事情的方法寫在這邊

onProgressUpdate  執行中,專門給Porgress條做監聽的方法

onPostExecute  執行後,最後的結果會在這邊。如果你Result的部分設定返回圖片,這裡就會噴Bitmap給你

方法會長以下這樣 

private class GetImage extends AsyncTask<String , Integer , Bitmap>{

        @Override
        protected void onPreExecute() {
            //執行前 設定可以在這邊設定
            super.onPreExecute();
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            //執行中 在背景做事情
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            //執行中 可以在這邊告知使用者進度
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //執行後 完成背景任務
            super.onPostExecute(bitmap);
        }
}
 

String... 和 int... 的部分可以參考我寫的一篇猛虎出閘
http://nikeru8.blogspot.tw/2017/08/java.html

如果是複數的Params,使用方式就是Params[0]、Params[1]依此類推...

Params[0] 就會是helloOne
Params[1] 就是 helloTwo

使用範例

private class GetImage extends AsyncTask<String , Integer , Bitmap>{

        private ProgressDialog progressBar;
        //進度條元件

        @Override
        protected void onPreExecute() {
            //執行前 設定可以在這邊設定
            super.onPreExecute();

            progressBar = new ProgressDialog(MainActivity.this);
            progressBar.setMessage("Loading...");
            progressBar.setCancelable(false);
            progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressBar.show();
            //初始化進度條並設定樣式及顯示的資訊。
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            //執行中 在背景做事情
            int progress = 0;
            for (String urlStr : params) {
                try {
                    URL url = new URL(urlStr);
                    Bitmap bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
                } catch (Exception  e) {
                    e.printStackTrace();
                }
                publishProgress(progress+=33);
                //有三張圖 每張圖33%
            }
            publishProgress(100);
            //最後達到100%
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            //執行中 可以在這邊告知使用者進度
            super.onProgressUpdate(values);
            progressBar.setProgress(values[0]);
            //取得更新的進度
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //執行後 完成背景任務
            super.onPostExecute(bitmap);

            progressBar.dismiss();
            //當完成的時候,把進度條消失
            imageView.setImageBitmap(bitmap);
        }
    }
 


完整程式碼

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

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:clickable="true"
        android:gravity="center"
        android:onClick="onbuttonclick"
        android:text="產生QRCode" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="45dp" />
</RelativeLayout>
 

MainActivity.java
public class MainActivity extends AppCompatActivity {


    private Activity activity;

    private ProgressDialog loadingDialog;

    //要生成的QRCode內容
    String QRCodeContent = "http://nikeru8.blogspot.tw/2017/04/third-partyxzingcore-qrcodejar.html";
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        activity = this;
        //參數
        imageView = (ImageView) findViewById(R.id.imageView);

        //設定loading Dialog
        loadingDialog = new ProgressDialog(activity);
        loadingDialog.setCanceledOnTouchOutside(false);
        loadingDialog.setCancelable(true);
        loadingDialog.setMessage("loading please wait...");
    }

    public void onbuttonclick(View view) {
        new GetImage().execute(QRCodeContent);
    }


    private class GetImage extends AsyncTask<String, Integer, Bitmap> {

        @Override
        protected void onPreExecute() {
            //執行前 設定可以在這邊設定

            loadingDialog.show();
            super.onPreExecute();
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            //執行中 在背景做事情
            int QRCodeWidth = 600;
            int QRCodeHeight = 600;
            //QRCode內容編碼
            Map hints = new EnumMap(EncodeHintType.class);
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

            MultiFormatWriter writer = new MultiFormatWriter();
            try {
                //ErrorCorrectionLevel容錯率分四級:L(7%) M(15%) Q(25%) H(30%)
                hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

                //建立QRCode的資料矩陣
                BitMatrix result = writer.encode(params[0], BarcodeFormat.QR_CODE, QRCodeWidth, QRCodeHeight, hints);

                //建立矩陣圖
                Bitmap bitmap = Bitmap.createBitmap(QRCodeWidth, QRCodeHeight, Bitmap.Config.ARGB_4444);
                for (int y = 0; y < QRCodeHeight; y++) {
                    for (int x = 0; x < QRCodeWidth; x++) {
                        bitmap.setPixel(x, y, result.get(x, y) ? Color.BLACK : Color.WHITE);
                    }
                }

                return bitmap;

            } catch (WriterException e) {
                e.printStackTrace();
                return null;
            }

        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            //執行中 可以在這邊告知使用者進度
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            //執行後 完成背景任務
            super.onPostExecute(bitmap);
            imageView.setImageBitmap(bitmap);
            loadingDialog.dismiss();
        }
    }
}

 


Demo


我拿QRCode寫個範例

因為QRCode如果跑太大張,通常都會造成畫面卡頓

使用AsyncTask就可以完美解決這問題

https://github.com/nikeru8/QRCodeDemo

1 則留言:

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...