環境:
SDK: android-17
IDE: eclipse
Device: Moto Atrix with 4.1.2
External Libraries: Volley
git clone --depth 1 https://android.googlesource.com/platform/frameworks/volley
Layout 為一個簡單的 GridView.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <GridView android:id="@+id/gridview" android:layout_width="match_parent" android:layout_height="wrap_content" android:drawSelectorOnTop="true" android:alwaysDrawnWithCache="false" android:fadeScrollbars="true" android:cacheColorHint="@android:color/transparent" android:numColumns="3" android:columnWidth="160dp"/> </RelativeLayout>
griview_row 就是一個很簡單的 imageview 而已
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageview" android:layout_width="160dp" android:layout_height="160dp" android:layout_centerInParent="true" android:scaleType="center" android:contentDescription="@null"/> </RelativeLayout>
實作過程中, 好像沒投影片那麼簡單, 投影片的 iamgeloader 使用 BitmapLruCache, 原本以為是包含在 volley 的 toolbox, 結果沒有, 必須自己去實作.
而本身 volley 則提供 DiskBaseCache, 簡單講就是暫存到外接記憶體.
Imageloader 的 cache, 必須實作 "ImageLoader.ImageCache" 這個 interface.
下面是實作部份, 此部份使用 picasso裡的 LruCache, 並且改成實作 volley 的 ImageCache.
public class BitmapLruCache implements ImageLoader.ImageCache { final LinkedHashMap<String, Bitmap> map; private final int maxSize; private int size; /** * Create a cache using an appropriate portion of the available RAM as the maximum size. */ public BitmapLruCache(Context context) { this(calculateMaxSize(context)); } /** * Create a cache with a given maximum size in bytes. */ public BitmapLruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("Max size must be positive."); } this.maxSize = maxSize; this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true); } private Bitmap get(String key) { if (key == null) { throw new NullPointerException("key == null"); } Bitmap mapValue; synchronized (this) { mapValue = map.get(key); if (mapValue != null) { return mapValue; } } return null; } private void set(String key, Bitmap bitmap) { if (key == null || bitmap == null) { throw new NullPointerException("key == null || bitmap == null"); } Bitmap previous; synchronized (this) { size += getBitmapBytes(bitmap); previous = map.put(key, bitmap); if (previous != null) { size -= getBitmapBytes(previous); } } trimToSize(maxSize); } private void trimToSize(int maxSize) { while (true) { String key; Bitmap value; synchronized (this) { if (size < 0 || (map.isEmpty() && size != 0)) { throw new IllegalStateException( getClass().getName() + ".sizeOf() is reporting inconsistent results!"); } if (size <= maxSize || map.isEmpty()) { break; } Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next(); key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= getBitmapBytes(value); } } } /** * Clear the cache. */ public final void clear() { trimToSize(-1); // -1 will evict 0-sized elements } private static int calculateMaxSize(Context context) { ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0; int memoryClass = am.getMemoryClass(); if (largeHeap && Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB) { memoryClass = ActivityManagerHoneycomb.getLargeMemoryClass(am); } return 1024 * 1024 * memoryClass / 6; } @Override public Bitmap getBitmap(String url) { return get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { set(url, bitmap); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private static class ActivityManagerHoneycomb { static int getLargeMemoryClass(ActivityManager activityManager) { return activityManager.getLargeMemoryClass(); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) private static class BitmapHoneycombMR1 { static int getByteCount(Bitmap bitmap) { return bitmap.getByteCount(); } } private static int getBitmapBytes(Bitmap bitmap) { int result; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { result = BitmapHoneycombMR1.getByteCount(bitmap); } else { result = bitmap.getRowBytes() * bitmap.getHeight(); } if (result < 0) { throw new IllegalStateException("Negative size: " + bitmap); } return result; } }
基本上主要程式部份, 除了初始話 ImageLoader, 接著就是在 GridView 的 adapter 使用 ImageLoader 就可.
以下只列出部份.
此部份在初始化 ImageLoader, 還有 Volley 最主要的 Request Queue.
RequestQueue mRequestQ; ImageLoader mImageLoader; mRequestQ = Volley.newRequestQueue(getActivity()); mImageLoader = new ImageLoader(mRequestQ, new BitmapLruCache(getActivity()));
此部份是在取得 image resource.
holder.container = mImageLoader.get(item.url, new ImageLoader.ImageListener() { @Override public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) { holder.iv.setImageBitmap(response.getBitmap()); } @Override public void onErrorResponse(VolleyError error) { Toast.makeText(getContext(), error.getMessage(), Toast.LENGTH_SHORT).show(); } }, 160,160);
執行結果如下 :
結論:
初步使用心得, 當 Imageloader 我個人認為就實作方面來說, 似乎還是有一些功夫需要作, 不過使用方面來說算是還滿簡單的.
另外值得一提的是, 對於某些會針對 Http-Header 來做某些行為的網站, 那使用 Volley 則必須要自己去實作 Request.
原始碼下載: VolleyExample.zip
沒有留言:
張貼留言