編輯:關於Android編程
/** * ImageLoader配置類, * * @author mrsimple */ public class ImageLoaderConfig { /** * 圖片緩存配置對象 */ public BitmapCache bitmapCache = new MemoryCache(); /** * 加載圖片時的loading和加載失敗的圖片配置對象 */ public DisplayConfig displayConfig = new DisplayConfig(); /** * 加載策略 */ public LoadPolicy loadPolicy = new SerialPolicy(); /** * */ public int threadCount = Runtime.getRuntime().availableProcessors() + 1; /** * @param count * @return */ public ImageLoaderConfig setThreadCount(int count) { threadCount = Math.max(1, threadCount); return this; } public ImageLoaderConfig setCache(BitmapCache cache) { bitmapCache = cache; return this; } public ImageLoaderConfig setLoadingPlaceholder(int resId) { displayConfig.loadingResId = resId; return this; } public ImageLoaderConfig setNotFoundPlaceholder(int resId) { displayConfig.failedResId = resId; return this; } public ImageLoaderConfig setLoadPolicy(LoadPolicy policy) { if (policy != null) { loadPolicy = policy; } return this; } }
都是很簡單的setter函數,但是不太一樣的是這些setter都是返回一個ImageLoaderConfig對象的,在這裡也就是返回了自身。這個設計是類似Builder模式的,便於用戶的鏈式調用,例如:
private void initImageLoader() { ImageLoaderConfig config = new ImageLoaderConfig() .setLoadingPlaceholder(R.drawable.loading) .setNotFoundPlaceholder(R.drawable.not_found) .setCache(new DoubleCache(this)) .setThreadCount(4) .setLoadPolicy(new ReversePolicy()); // 初始化 SimpleImageLoader.getInstance().init(config); }
對於Builder模式不太了解的同學可以參考 Android源碼分析之Builder模式。構建好配置對象之後我們就可以通過這個配置對象來初始化SimpleImageLoader了。SimpleImageLoader會根據配置對象來初始化一些內部策略,例如緩存策略、線程數量等。調用init方法後整個ImageLoader就正式啟動了。
/** * 圖片加載類,支持url和本地圖片的uri形式加載.根據圖片路徑格式來判斷是網絡圖片還是本地圖片,如果是網絡圖片則交給SimpleNet框架來加載, * 如果是本地圖片那麼則交給mExecutorService從sd卡中加載 * .加載之後直接更新UI,無需用戶干預.如果用戶設置了緩存策略,那麼會將加載到的圖片緩存起來.用戶也可以設置加載策略,例如順序加載{@see * SerialPolicy}和逆向加載{@see ReversePolicy}. * * @author mrsimple */ public final class SimpleImageLoader { /** SimpleImageLoader實例 */ private static SimpleImageLoader sInstance; /** 網絡請求隊列 */ private RequestQueue mImageQueue; /** 緩存 */ private volatile BitmapCache mCache = new MemoryCache(); /** 圖片加載配置對象 */ private ImageLoaderConfig mConfig; private SimpleImageLoader() { } /** * 獲取ImageLoader單例 * * @return */ public static SimpleImageLoader getInstance() { if (sInstance == null) { synchronized (SimpleImageLoader.class) { if (sInstance == null) { sInstance = new SimpleImageLoader(); } } } return sInstance; } /** * 初始化ImageLoader,啟動請求隊列 * @param config 配置對象 */ public void init(ImageLoaderConfig config) { mConfig = config; mCache = mConfig.bitmapCache; checkConfig(); mImageQueue = new RequestQueue(mConfig.threadCount); mImageQueue.start(); } private void checkConfig() { if (mConfig == null) { throw new RuntimeException( "The config of SimpleImageLoader is Null, please call the init(ImageLoaderConfig config) method to initialize"); } if (mConfig.loadPolicy == null) { mConfig.loadPolicy = new SerialPolicy(); } if (mCache == null) { mCache = new NoCache(); } } public void displayImage(ImageView imageView, String uri) { displayImage(imageView, uri, null, null); } public void displayImage(final ImageView imageView, final String uri, final DisplayConfig config, final ImageListener listener) { BitmapRequest request = new BitmapRequest(imageView, uri, config, listener); // 加載的配置對象,如果沒有設置則使用ImageLoader的配置 request.displayConfig = request.displayConfig != null ? request.displayConfig : mConfig.displayConfig; // 添加對隊列中 mImageQueue.addRequest(request); } // 代碼省略... /** * 圖片加載Listener * * @author mrsimple */ public static interface ImageListener { public void onComplete(ImageView imageView, Bitmap bitmap, String uri); } }
public BitmapRequest(ImageView imageView, String uri, DisplayConfig config, ImageListener listener) { mImageViewRef = new WeakReference(imageView); displayConfig = config; imageListener = listener; imageUri = uri; // 設置ImageView的tag為圖片的uri imageView.setTag(uri); imageUriMd5 = Md5Helper.toMD5(imageUri); }
/** * 請求隊列, 使用優先隊列,使得請求可以按照優先級進行處理. [ Thread Safe ] * * @author mrsimple */ public final class RequestQueue { /** * 請求隊列 [ Thread-safe ] */ private BlockingQueuemRequestQueue = new PriorityBlockingQueue (); /** * 請求的序列化生成器 */ private AtomicInteger mSerialNumGenerator = new AtomicInteger(0); /** * 默認的核心數 */ public static int DEFAULT_CORE_NUMS = Runtime.getRuntime().availableProcessors() + 1; /** * CPU核心數 + 1個分發線程數 */ private int mDispatcherNums = DEFAULT_CORE_NUMS; /** * NetworkExecutor,執行網絡請求的線程 */ private RequestDispatcher[] mDispatchers = null; /** * */ protected RequestQueue() { this(DEFAULT_CORE_NUMS); } /** * @param coreNums 線程核心數 * @param httpStack http執行器 */ protected RequestQueue(int coreNums) { mDispatcherNums = coreNums; } /** * 啟動RequestDispatcher */ private final void startDispatchers() { mDispatchers = new RequestDispatcher[mDispatcherNums]; for (int i = 0; i < mDispatcherNums; i++) { mDispatchers[i] = new RequestDispatcher(mRequestQueue); mDispatchers[i].start(); } } public void start() { stop(); startDispatchers(); } /** * 停止RequestDispatcher */ public void stop() { if (mDispatchers != null && mDispatchers.length > 0) { for (int i = 0; i < mDispatchers.length; i++) { mDispatchers[i].interrupt(); } } } /** * 不能重復添加請求 * @param request */ public void addRequest(BitmapRequest request) { if (!mRequestQueue.contains(request)) { request.serialNum = this.generateSerialNumber(); mRequestQueue.add(request); } else { Log.d("", "### 請求隊列中已經含有"); } } private int generateSerialNumber() { return mSerialNumGenerator.incrementAndGet(); } }
final class RequestDispatcher extends Thread { /** * 網絡請求隊列 */ private BlockingQueuemRequestQueue; /** * @param queue 圖片加載請求隊列 */ public RequestDispatcher(BlockingQueue queue) { mRequestQueue = queue; } @Override public void run() { try { while (!this.isInterrupted()) { final BitmapRequest request = mRequestQueue.take(); if (request.isCancel) { continue; } // 解析圖片schema final String schema = parseSchema(request.imageUri); // 根據schema獲取對應的Loader Loader imageLoader = LoaderManager.getInstance().getLoader(schema); // 加載圖片 imageLoader.loadImage(request); } } catch (InterruptedException e) { Log.i("", "### 請求分發器退出"); } } /** * 這裡是解析圖片uri的格式,uri格式為: schema:// + 圖片路徑。 */ private String parseSchema(String uri) { if (uri.contains("://")) { return uri.split("://")[0]; } else { Log.e(getName(), "### wrong scheme, image uri is : " + uri); } return ""; } }
第一個重點就是run函數了,不斷地從隊列中獲取請求,然後解析到圖片uri的schema,從schema的格式就可以知道它是存儲在哪裡的圖片。例如網絡圖片對象的schema是http或者https,sd卡存儲的圖片對應的schema為file。根據schema我們從LoaderManager中獲取對應的Loader來加載圖片,這個設計保證了SimpleImageLoader可加載圖片類型的可擴展性,這就是為什麼會增加loader這個包的原因。用戶只需要根據uri的格式來構造圖片uri,並且實現自己的Loader類,然後將Loader對象注入到LoaderManager即可,後續我們會再詳細說明。
這裡的另一個重點是parseSchema函數,它的職責是解析圖片uri的格式,uri格式為: schema:// + 圖片路徑,例如網絡圖片的格式為http://xxx.image.jpg,而本地圖片的uri為file:///sdcard/xxx/image.jpg。如果你要實現自己的Loader來加載特定的格式,那麼它的uri格式必須以schema://開頭,否則解析會錯誤,例如可以為drawable://image,然後你注冊一個schema為"drawable"的Loader到LoaderManager中,SimpleImageLoader在加載圖片時就會使用你注冊的Loader來加載圖片,這樣就可以應對用戶的多種多樣的需求。如果不能擁抱變化那就不能稱之為框架了,應該叫功能模塊。
demo效果增加數據: 刪除數據 修改數據 SQLite介紹SQLite,是一款輕型的數據庫,是遵守ACID的關系型數據庫管理系統,它包含在一個相對
首先看一張國內Top500 Android應用中它們用到的第三方推送以及所占數量:現在總結下Android平台下幾種推送方案的基本情況以及優缺點:一、使用GCM(Goog
Android存儲五大方式:1 使用SharedPreferences存儲數據2 文件存儲數據3 SQLite數據庫存儲數據4 使用ContentProvider存儲數據
本文結合之前的動態創建fragment來進行一個實踐,來實現用Fragment創建一個選項卡項目布局<LinearLayout xmlns:android=http