這次程式是從這邊出來的
http://android-developers.blogspot.tw/2010/07/multithreading-for-performance.html
如果要下載一張圖片, 用下面這個方法就可以完成。
所截取到的inputstream透過decodeStream可以變成一張bitmap, 但是在網路速度比較慢的狀態會出現一些問題, 因此用下面的方法來修正上面的問題。
那麼在下載的時候, 是無法讓畫面滑動的。
事實上Android也不允許你在主畫面進行一些複雜的程式, 比如說下載檔案, 這時候就會產生ANR視窗來阻止你, 在之前的 無痛執行緒 當中就有詳細的說明。
當你直接使用如下圖
就會產生錯誤訊息
因此我們需要加入一些執行緒來處理下載的任務。
在如何使用Thread和Handler裡面, 我們用一個Thread跟Handler的物件來處理, 其實可以用Android提供的AsyncTask的方法更為方便。
寫成AsyncTask的時候, 開發者只需要使用下面的方法, 就可以輕鬆下載。
而你的AsyncTask類別就可以這樣寫
這時候ImageView就會被拿來重複利用, 如果沒有清除, 就會出現之前的畫面。
而將之前的ImageDownload改用下面的方法來存取。
透過ImageView得到相對應的下載
程式碼
http://uploadingit.com/file/vldfceemuyrbjsqh/ImageDownloader.zip
http://android-developers.blogspot.tw/2010/07/multithreading-for-performance.html
如果要下載一張圖片, 用下面這個方法就可以完成。
static Bitmap downloadBitmap(String url) {
final AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
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 {
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// Could provide a more explicit error message for IOException or IllegalStateException
getRequest.abort();
Log.w("ImageDownloader", "Error while retrieving bitmap from " + url, e.toString());
} finally {
if (client != null) {
client.close();
}
}
return null;
}
所截取到的inputstream透過decodeStream可以變成一張bitmap, 但是在網路速度比較慢的狀態會出現一些問題, 因此用下面的方法來修正上面的問題。
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int byte = read();
if (byte < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
但是直接使用上面的方法, 假設在ListView上面的每一列, 都放上一張等待下載的圖,那麼在下載的時候, 是無法讓畫面滑動的。
事實上Android也不允許你在主畫面進行一些複雜的程式, 比如說下載檔案, 這時候就會產生ANR視窗來阻止你, 在之前的 無痛執行緒 當中就有詳細的說明。
當你直接使用如下圖
就會產生錯誤訊息
因此我們需要加入一些執行緒來處理下載的任務。
在如何使用Thread和Handler裡面, 我們用一個Thread跟Handler的物件來處理, 其實可以用Android提供的AsyncTask的方法更為方便。
寫成AsyncTask的時候, 開發者只需要使用下面的方法, 就可以輕鬆下載。
public class ImageDownloader {
public void download(String url, ImageView imageView) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
task.execute(url);
}
}
/* class BitmapDownloaderTask, see below */
}
而你的AsyncTask類別就可以這樣寫
class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
private String url;
private final WeakReference<ImageView> imageViewReference;
public BitmapDownloaderTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
// Actual download method, run in the task thread
protected Bitmap doInBackground(String... params) {
// params comes from the execute() call: params[0] is the url.
return downloadBitmap(params[0]);
}
@Override
// Once the image is downloaded, associates it to the imageView
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
看起來似乎很完美, 但是其實你在滑動ListView的時候, 其實他會不斷的去存取getView這個方法, 當畫面只能呈現四個items的時候, listview滑動到第五個item, 而第一個item消失時,這時候ImageView就會被拿來重複利用, 如果沒有清除, 就會出現之前的畫面。
static class DownloadedDrawable extends ColorDrawable {
private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;
public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
super(Color.BLACK);
bitmapDownloaderTaskReference =
new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
}
public BitmapDownloaderTask getBitmapDownloaderTask() {
return bitmapDownloaderTaskReference.get();
}
}
而將之前的ImageDownload改用下面的方法來存取。
public void download(String url, ImageView imageView) {
if (cancelPotentialDownload(url, imageView)) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute(url, cookie);
}
}
透過ImageView得到相對應的下載
private static boolean cancelPotentialDownload(String url, ImageView imageView) {
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if (bitmapDownloaderTask != null) {
String bitmapUrl = bitmapDownloaderTask.url;
if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
bitmapDownloaderTask.cancel(true);
} else {
// The same URL is already being downloaded.
return false;
}
}
return true;
}
程式碼
http://uploadingit.com/file/vldfceemuyrbjsqh/ImageDownloader.zip