在 Android 中使用 AsyncTask 下载图像

本教程介绍如何使用 Android 中的 AsyncTask 下载 Image。下面的示例在下载过程中显示进度条的同时下载图像。

了解 Android AsyncTask

异步任务使你可以实现 MultiThreading 而不会弄脏线程。AsyncTask 可以正确,方便地使用 UI 线程。它允许执行后台操作并在 UI 线程上传递结果。如果你正在执行与 UI 相关的隔离操作,例如下载数据以显示在列表中,请继续使用 AsyncTask。

  • 理想情况下,AsyncTasks 应该用于短操作(最多几秒钟)。
  • 异步任务由 3 种泛型类型定义,称为 Params,Progress 和 Result,以及 4 个步骤,称为 onPreExecute()doInBackground()onProgressUpdate()onPostExecute()
  • onPreExecute() 中,你可以定义代码,这些代码需要在后台处理开始之前执行。
  • doInBackground 有需要在后台执行的代码,这里在 doInBackground() 中我们可以通过 publishProgress() 方法多次向结果线程发送结果,通知后台处理已经完成,我们可以简单地返回结果。
  • onProgressUpdate() 方法从 doInBackground() 方法接收进度更新,通过 publishProgress() 方法发布,此方法可以使用此进度更新来更新事件线程
  • onPostExecute() 方法处理 doInBackground() 方法返回的结果。
  • 使用的泛型类型是
    • 参数,执行时发送给任务的参数类型
    • 进度,后台计算期间发布的进度单元的类型。
    • 结果,后台计算结果的类型。
  • 如果异步任务不使用任何类型,则可以将其标记为 Void 类型。
  • 可以通过调用 cancel(boolean) 方法取消正在运行的异步任务。

使用 Android AsyncTask 下载图像

你的 .xml 版面

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

<Button
    android:id="@+id/downloadButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Click Here to Download" />

<ImageView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:contentDescription="Your image will appear here" />

</LinearLayout>

.java 类

package com.javatechig.droid;

import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class ImageDownladerActivity extends Activity {

    private ImageView downloadedImg;
    private ProgressDialog simpleWaitDialog;
    private String downloadUrl = "http://www.9ori.com/store/media/images/8ab579a656.jpg";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.asynch);
        Button imageDownloaderBtn = (Button) findViewById(R.id.downloadButton);

        downloadedImg = (ImageView) findViewById(R.id.imageView);

        imageDownloaderBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                new ImageDownloader().execute(downloadUrl);
            }

        });
    }

    private class ImageDownloader extends AsyncTask {

        @Override
        protected Bitmap doInBackground(String... param) {
            // TODO Auto-generated method stub
            return downloadBitmap(param[0]);
        }

        @Override
        protected void onPreExecute() {
            Log.i("Async-Example", "onPreExecute Called");
            simpleWaitDialog = ProgressDialog.show(ImageDownladerActivity.this,
                    "Wait", "Downloading Image");

        }

        @Override
        protected void onPostExecute(Bitmap result) {
            Log.i("Async-Example", "onPostExecute Called");
            downloadedImg.setImageBitmap(result);
            simpleWaitDialog.dismiss();

        }

        private Bitmap downloadBitmap(String url) {
            // initilize the default HTTP client object
            final DefaultHttpClient client = new DefaultHttpClient();

            //forming a HttpGet request 
            final HttpGet getRequest = new HttpGet(url);
            try {

                HttpResponse response = client.execute(getRequest);

                //check 200 OK for success
                final int statusCode = response.getStatusLine().getStatusCode();

                if (statusCode != HttpStatus.SC_OK) {
                    Log.w("ImageDownloader", "Error " + statusCode + 
                            " while retrieving bitmap from " + url);
                    return null;

                }

                final HttpEntity entity = response.getEntity();
                if (entity != null) {
                    InputStream inputStream = null;
                    try {
                        // getting contents from the stream 
                        inputStream = entity.getContent();

                        // decoding stream data back into image Bitmap that android understands
                        final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

                        return bitmap;
                    } finally {
                        if (inputStream != null) {
                            inputStream.close();
                        }
                        entity.consumeContent();
                    }
                }
            } catch (Exception e) {
                // You Could provide a more explicit error message for IOException
                getRequest.abort();
                Log.e("ImageDownloader", "Something went wrong while" +
                        " retrieving bitmap from " + url + e.toString());
            } 

            return null;
        }
    }
}

由于目前没有例子的评论字段(或者我没有找到它或我没有获得它的许可),这里有一些评论:

这是使用 AsyncTask 可以完成的一个很好的例子。

然而,该示例目前存在问题

  • 可能的内存泄漏
  • 如果在异步任务完成之前不久有屏幕旋转,应用程序崩溃。

详情见: