Android架構(gòu)那些事之第三方庫的隔離
在進(jìn)入主題之前我們先說一下app客戶端為什么需要有一個(gè)好的架構(gòu)。
我們都知道一個(gè)好的架構(gòu)會(huì)使我們的開發(fā)變得事半功倍。
設(shè)計(jì)架構(gòu)的目的在于使我們的客戶端易于擴(kuò)展、方便單元測(cè)試、可復(fù)用。
做到使模塊之間低耦合,模塊內(nèi)部高內(nèi)聚。
我們?cè)陂_發(fā)的過程中會(huì)不可避免的引用一些第三方庫,比如網(wǎng)絡(luò)請(qǐng)求庫、圖片加載庫等等。就拿我們的圖片加載庫來說,程序中不會(huì)只有一個(gè)地方來引用到此庫,可能有N個(gè)類會(huì)用到此庫來顯示圖片。比如我們現(xiàn)在使用Universal-Image-Loader來展示客戶端需要的圖片,客戶端總共有10個(gè)類使用該來顯示圖片。迭代了兩個(gè)版本后老板突然說APP經(jīng)常出現(xiàn)顯示圖片出現(xiàn)OOM的問題,我們需要將Universal-Image-Loader換成更高效的Picasso來顯示圖片。
聽到這個(gè)需求我們的***反應(yīng)是"天哪,鬼知道項(xiàng)目里有多少個(gè)地方引用了ImageLoader庫,我們得改多少代碼,萬一改代碼的時(shí)候引發(fā)了其他的bug怎么辦"。
問題來了我們應(yīng)該如何避免這種“牽一發(fā)而動(dòng)全身”的囧況。
好了,我們先來看下我們平常是怎么在項(xiàng)目中引用圖片加載庫的。
before.png
上圖是我們大多數(shù)人的做法。那么我們?cè)趺床拍茏龅綋Q了一個(gè)第三方加載庫而是這四個(gè)引用類不做改動(dòng)呢。
下面看下我們重新新設(shè)計(jì)之后的引用流程圖
after.png
從上圖我們能看到我們通過一個(gè)中間層來引用“第三方圖片加載庫”。這樣做的好處是不管第三方圖片加載庫你換成Picasso還是Glide我們改變的只是這個(gè)中間層,其他的我們一行代碼都不需要改動(dòng)。
如果當(dāng)時(shí)你是這樣設(shè)計(jì)的當(dāng)老板讓你把Universal-Image-Loader換成Picasso時(shí)你一行代碼也不用改動(dòng)只需要擴(kuò)展一個(gè)類就可以了。好了話不多說 我們來看代碼如何設(shè)計(jì)。
我這里是使用代理模式來實(shí)現(xiàn)代碼與圖片加載庫的隔離的。
首先抽象一個(gè)ImageLoader接口
- **
- * 圖片加載器功能接口;
- * 添加或者替換新的圖片加載器實(shí)現(xiàn)該接口即可
- */public interface ImageLoader { /**
- * Init ImageLoader
- */
- void init(Context context); /**
- * Show Image
- *
- * @param imageUrl
- * @param imageView
- * @param defaultImage
- */
- void displayImage(String imageUrl, ImageView imageView, int defaultImage);
- }
我們當(dāng)前是使用UniversalImageLoader來展示項(xiàng)目中的圖片我們就建一個(gè)UniversalImageLoader類來實(shí)現(xiàn)上面的接口
- public class UniversalImageLoader implements ImageLoader { private final long discCacheLimitTime = 3600 * 24 * 15L; private com.nostra13.universalimageloader.core.ImageLoader imageLoader = com.nostra13.universalimageloader.core.ImageLoader.getInstance(); @Override
- public void init(Context context) { if (!imageLoader.isInited()) {
- ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
- context)
- .threadPriority(Thread.NORM_PRIORITY)
- .denyCacheImageMultipleSizesInMemory()
- .memoryCache(new WeakMemoryCache())
- .memoryCacheSize((2 * 1024 * 1024))
- .memoryCacheSizePercentage(13)
- .discCacheFileNameGenerator(new Md5FileNameGenerator())
- .discCache( new LimitedAgeDiskCache(StorageUtils
- .getCacheDirectory(context),
- discCacheLimitTime))
- .tasksProcessingOrder(QueueProcessingType.LIFO).build();
- com.nostra13.universalimageloader.core.ImageLoader.getInstance().init(config);
- }
- } @Override
- public void displayImage(String uri, ImageView img, int default_pic) {
- DisplayImageOptions options = new DisplayImageOptions.Builder()
- .showImageOnLoading(default_pic)
- .showImageForEmptyUri(default_pic).showImageOnFail(default_pic)
- .cacheInMemory(true).cacheOnDisc(true)
- .bitmapConfig(Bitmap.Config.RGB_565)
- .displayer(new SimpleBitmapDisplayer()).build();
- imageLoader.displayImage(uri, img, options);
- }
接下來我們寫一個(gè)代理類來幫我們實(shí)現(xiàn)圖片加載的任務(wù)
- /**
- * 圖片加載代理類,所有的圖片操作都通過該代理類去實(shí)現(xiàn);
- * 如果要改變圖片加載框架,只需要在該類里替換相應(yīng)的圖片加載框架即可,客戶端所有引用的圖片操作都不需要修改
- */public class ImageLoaderProxy implements ImageLoader { private ImageLoader imageLoader;//代理對(duì)象
- private static ImageLoaderProxy imageLoaderProxy; public static ImageLoaderProxy getInstance() { if (imageLoaderProxy == null) {
- imageLoaderProxy = new ImageLoaderProxy();
- } return imageLoaderProxy;
- } public ImageLoaderProxy() {
- imageLoader= new UniversalImageLoader();
- } @Override
- public void init(Context context) {
- imageLoader.init(context);
- } @Override
- public void displayImage(String imageUrl, ImageView imageView, int defaultImage) {
- imageLoader.displayImage(imageUrl, imageView, defaultImage);
- }
- }
這樣客戶端所有需要顯示圖片的地方只需要調(diào)用代理類的圖片顯示方法即可 ImageLoaderProxy.getInstance().displayImage();
當(dāng)老板讓我們換成Picasso來完成圖片加載時(shí) ,我們只需增加一個(gè) PicassoImageLoader類然后將代理類中的這行代碼 imageLoaderProxy = new UniversalImageLoader();換成imageLoaderProxy = new PicassoImageLoader()即可。
怎么樣我們只改動(dòng)一行代碼就替換了一個(gè)圖片加載庫方便吧。





























