本文給大家演示異步加載圖片的分析過程。讓大家了解異步加載圖片的好處,以及如何更新UI。 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas./apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:text="圖片區(qū)域開始" android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/imageView1" android:layout_height="wrap_content" android:src="@drawable/icon" android:layout_width="wrap_content" /> <ImageView android:id="@+id/imageView2" android:layout_height="wrap_content" android:src="@drawable/icon" android:layout_width="wrap_content" /> <ImageView android:id="@+id/imageView3" android:layout_height="wrap_content" android:src="@drawable/icon" android:layout_width="wrap_content" /> <ImageView android:id="@+id/imageView4" android:layout_height="wrap_content" android:src="@drawable/icon" android:layout_width="wrap_content" /> <ImageView android:id="@+id/imageView5" android:layout_height="wrap_content" android:src="@drawable/icon" android:layout_width="wrap_content" /> <TextView android:text="圖片區(qū)域結(jié)束" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 我們將演示的過程是異步從服務(wù)器上下載5張不同圖片,依次放入這5個ImageView。上下2個TextView 是為了方便我們看是否阻塞了UI的顯示。 <uses-permission android:name="android.permission.INTERNET" /> 1)Handler+Runnable模式 package com.szy.textviewimagedemo; import java.io.IOException; import java.net.URL; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.widget.ImageView; /** *@author coolszy *@date 2012-2-13 *@blog http://blog. * */ public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); loadImage("http://www./images/logo_new.gif", R.id.imageView2); loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4); loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); } private Handler handler = new Handler(); private void loadImage(final String url, final int id) { handler.post(new Runnable() { public void run() { Drawable drawable = null; try { drawable = Drawable.createFromStream(new URL(url).openStream(), "image.gif"); } catch (IOException e) { Log.i("MainActivity", e.getMessage()); } if (drawable == null) { Log.i("MainActivity", "null drawable"); } else { Log.i("MainActivity", "not null drawable"); } // 為了測試緩存而模擬的網(wǎng)絡(luò)延時 SystemClock.sleep(2000); ((ImageView) MainActivity.this.findViewById(id)).setImageDrawable(drawable); } }); } } 2)Handler+Thread+Message模式 package com.szy.textviewimagedemo; import java.io.IOException; import java.net.URL; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.util.Log; import android.widget.ImageView; /** *@author coolszy *@date 2012-2-13 *@blog http://blog. * */ public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.i("MainActivity", "MainThread ID:"+Thread.currentThread().getId()); loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); loadImage("http://www./images/logo_new.gif", R.id.imageView2); loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4); loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); } final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { Log.i("MainActivity", "UpdateUIThread ID:"+Thread.currentThread().getId()); ((ImageView) MainActivity.this.findViewById(msg.arg1)).setImageDrawable((Drawable) msg.obj); } }; // 采用handler+Thread模式實現(xiàn)多線程異步加載 private void loadImage(final String url, final int id) { Thread thread = new Thread() { @Override public void run() { Drawable drawable = null; try { Log.i("MainActivity", "Thread ID:"+Thread.currentThread().getId()); drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); } catch (IOException e) { Log.i("MainActivity", e.getMessage()); } // 模擬網(wǎng)絡(luò)延時 SystemClock.sleep(2000); Message message = handler.obtainMessage(); message.arg1 = id; message.obj = drawable; handler.sendMessage(message); } }; thread.start(); thread = null; } } 這時候我們可以看到實現(xiàn)了異步加載, 界面打開時,五個ImageView都是沒有圖的,然后在各自線程下載完后才把圖自動更新上去。 package com.szy.textviewimagedemo; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.widget.ImageView; /** *@author coolszy *@date 2012-2-13 *@blog http://blog. * */ public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.i("MainActivity", "MainThread ID:"+Thread.currentThread().getId()); loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); loadImage("http://www./images/logo_new.gif", R.id.imageView2); loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4); loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); } private Handler handler = new Handler(); private ExecutorService executorService = Executors.newFixedThreadPool(5); // 引入線程池來管理多線程 private void loadImage(final String url, final int id) { executorService.submit(new Runnable() { public void run() { try { Log.i("MainActivity", "Thread ID:"+Thread.currentThread().getId()); final Drawable drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); // 模擬網(wǎng)絡(luò)延時 SystemClock.sleep(2000); handler.post(new Runnable() { public void run() { Log.i("MainActivity", "UpdateUIThread ID:"+Thread.currentThread().getId()); ((ImageView) MainActivity.this.findViewById(id)).setImageDrawable(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); } } 這里我們象第一步一樣使用了 package com.szy.textviewimagedemo; import java.lang.ref.SoftReference; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.SystemClock; import android.util.Log; /** *@author coolszy *@date 2012-2-13 *@blog http://blog. */ public class AsyncImageLoader { // 為了加快速度,在內(nèi)存中開啟緩存(主要應(yīng)用于重復(fù)圖片較多時,或者同一個圖片要多次被訪問,比如在ListView時來回滾動) public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); private ExecutorService executorService = Executors.newFixedThreadPool(5); // 固定五個線程來執(zhí)行任務(wù) private final Handler handler = new Handler(); /** * * @param imageUrl * 圖像url地址 * @param callback * 回調(diào)接口 * @return 返回內(nèi)存中緩存的圖像,第一次加載返回null */ public Drawable loadDrawable(final String imageUrl, final ImageCallback callback) { // 如果緩存過就從緩存中取出數(shù)據(jù) if (imageCache.containsKey(imageUrl)) { SoftReference<Drawable> softReference = imageCache.get(imageUrl); if (softReference.get() != null) { Log.i("MainActivity", "圖片存在緩存中."); return softReference.get(); } } // 緩存中沒有圖像,則從網(wǎng)絡(luò)上取出數(shù)據(jù),并將取出的數(shù)據(jù)緩存到內(nèi)存中 executorService.submit(new Runnable() { public void run() { try { Log.i("MainActivity", "下載圖片..."); final Drawable drawable = loadImageFromUrl(imageUrl); imageCache.put(imageUrl, new SoftReference<Drawable>(drawable)); handler.post(new Runnable() { public void run() { callback.imageLoaded(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); return null; } // 從網(wǎng)絡(luò)上取數(shù)據(jù)方法 protected Drawable loadImageFromUrl(String imageUrl) { try { // 測試時,模擬網(wǎng)絡(luò)延時,實際時這行代碼不能有 SystemClock.sleep(2000); return Drawable.createFromStream(new URL(imageUrl).openStream(), "image.png"); } catch (Exception e) { throw new RuntimeException(e); } } // 對外界開放的回調(diào)接口 public interface ImageCallback { // 注意 此方法是用來設(shè)置目標(biāo)對象的圖像資源 public void imageLoaded(Drawable imageDrawable); } } 說明: package com.szy.textviewimagedemo; import android.app.Activity; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.widget.ImageView; /** *@author coolszy *@date 2012-2-13 *@blog http://blog. * */ public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); loadImage("http://www./images/logo_new.gif", R.id.imageView2); loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); loadImage("http:///www/images/csdnindex_logo.gif", R.id.imageView4); loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); } private AsyncImageLoader asyncImageLoader = new AsyncImageLoader(); // 引入線程池,并引入內(nèi)存緩存功能,并對外部調(diào)用封裝了接口,簡化調(diào)用過程 private void loadImage(final String url, final int id) { // 如果緩存過就會從緩存中取出圖像,ImageCallback接口中方法也不會被執(zhí)行 Drawable cacheImage = asyncImageLoader.loadDrawable(url, new AsyncImageLoader.ImageCallback() { // 請參見實現(xiàn):如果第一次加載url時下面方法會執(zhí)行 public void imageLoaded(Drawable imageDrawable) { ((ImageView) findViewById(id)).setImageDrawable(imageDrawable); } }); if (cacheImage != null) { ((ImageView) findViewById(id)).setImageDrawable(cacheImage); } } } |
|