AsyncTask做非同步處理(以圖片下載為例子)

AsyncTask 和Thread的功能幾乎相同, 主要增加一個新的執行緒, 讓一些比較耗時的功能與主執行緒(UI thread)分開處理相較於Thread, 如果處理完成還需要一個Handler來通知Threas的完成而Async則是提供了執行緒結束的方法, 可讓使用的人方便使用, 不需要再一個Handle來接

以下是範例
使用AsyncTask的重要方法

1.AsyncTask<String, Void, Bitmap>繼承子類別時, 需要傳入三個類別, 可以Void, 就表示不傳入任何東西
2.protected Bitmap doInBackground(String… params)主要處理非同步的部分
3.protected void onPostExecute(Bitmap bitmap)非同步處理完成會到這邊

AndroidManifest加入以下, 增加相關權限

AndroidManifest.xml

<uses-permission android:name=”android.permission.INTERNET”/>
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE” />
 

ImageCompleteListener.java

  
//下載完成後回傳
public interface ImageCompleteListener {
      public void onImageSaveComplete(Bitmap bitmap);

      public void onImageSaveFailed(Exception exception);
}

建立一個Interface 以處理AsyncTask完成後的通知

ImageDownloaderTask.java

 
public class ImageDownloaderTask extends AsyncTask&amp;amp;lt;String, Void, Bitmap&amp;amp;gt; {

    private ImageCompleteListener imageCompleteListener;
    private String path;
    private String fileName;

    public ImageDownloaderTask(String path, String fileName, ImageCompleteListener imageCompleteListener) {
        this.path = path;
        this.fileName = fileName;
        this.imageCompleteListener = imageCompleteListener;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        return downloadBitmap(params[0]);
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (bitmap == null) imageCompleteListener.onImageSaveFailed(new Exception());
        imageCompleteListener.onImageSaveComplete(bitmap);

        if (isCancelled()) bitmap = null;

    }

    private Bitmap downloadBitmap(String url) {
        HttpURLConnection urlConnection = null;
        try {
            URL uri = new URL(url);
            urlConnection = (HttpURLConnection) uri.openConnection();

            int statusCode = urlConnection.getResponseCode();
            if (statusCode != 200) {
                return null;
            }

            InputStream inputStream = urlConnection.getInputStream();
            if (inputStream != null) {
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

                urlConnection.disconnect();

                // 取得外部儲存裝置路徑
                // 開啟檔案
                File file = new File(path, fileName);
                // 開啟檔案串流
                FileOutputStream out = null;

                out = new FileOutputStream(file);
                // 將 Bitmap壓縮成指定格式的圖片並寫入檔案串流
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                // 刷新串流 關閉檔案
                out.flush();
                out.close();

                return bitmap;
            } else {
                return null;
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return null;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

建立一個ImageDownloadTask.java, 主要處理下載的邏輯在doInBackground裡面直接放進執行下載的部分, 完成之後會回到onPostExecute, 來通知MainActivity已經下載完成

MainActivity.java

 
public class MainActivity extends AppCompatActivity {
    private final static int REQUEST_EXTERNAL_STORAGE = 1000;

    private ImageView imageView = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) MainActivity.this.findViewById(R.id.imageView);
        //取得權限
        int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    this,
                    new String[]{
                            Manifest.permission.WRITE_EXTERNAL_STORAGE,
                            Manifest.permission.READ_EXTERNAL_STORAGE,
                            Manifest.permission.INTERNET},
                    REQUEST_EXTERNAL_STORAGE);
        } else {
            startImageDownload();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_EXTERNAL_STORAGE:
                if (grantResults.length &amp;amp;gt; 0 &amp;amp;amp;&amp;amp;amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //取得權限,進行檔案存取
                    startImageDownload();
                } else {
                    //使用者拒絕權限,停用檔案存取功能
                    Toast.makeText(this, &amp;quot;請開啟權限&amp;quot;, Toast.LENGTH_SHORT).show();

                }
                return;
        }
    }

    private void startImageDownload() {

        //這裡處理儲存位置
        String path = Environment.getExternalStorageDirectory().toString();
        //這裡設置
        String filename = &amp;quot;myFileName.jpg&amp;quot;;
        //設置下載地址
        String downloadUrl = &amp;quot;https://i.imgur.com/GTMs4pm.jpg&amp;quot;;

        ImageDownloaderTask imageDownloaderTask = new ImageDownloaderTask(path, filename, new ImageCompleteListener() {
            @Override
            public void onImageSaveComplete(Bitmap bitmap) {
                Log.d(this.getClass().getSimpleName(), &amp;quot;success!!&amp;quot;);
                imageView.setImageBitmap(bitmap);
            }

            @Override
            public void onImageSaveFailed(Exception exception) {
                Log.e(this.getClass().getSimpleName(), &amp;quot;Failed!!&amp;quot;);
            }
        });

        imageDownloaderTask.execute(downloadUrl);
    }
}

Activity啟動時檢查是否大於API23, 因Android 6.0 以上需要權限的認證.檢查完成後就可以做檔案下載這樣簡單的AsyncTask實做檔案下載就可以完成

github連結:
https://github.com/shineshane2000/Android_downloadImage

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *