当前位置: 首页 > 科技观察

第三方库对于Android架构中那些东西的隔离

时间:2023-03-18 10:56:48 科技观察

进入正题之前,先说说为什么app客户端需要有一个好的架构。我们都知道好的架构会让我们的开发更有效率。设计架构的目的是让我们的客户端易于扩展,易于单元测试和可重用。实现模块之间的低耦合和模块内部的高内聚。在开发过程中,我们难免会参考一些第三方库,比如网络请求库、图片加载库等。以我们的图片加载库为例,程序中不会只有一个地方引用这个库,可能有N个类会用到这个库来显示图片。比如我们现在使用Universal-Image-Loader来展示客户端需要的图片。客户端一共有10个类用这个来展示图片。迭代了两个版本,老大突然说APP在显示图片时经常出现OOM问题,需要把Universal-Image-Loader换成更高效的Picasso来显示图片。听到这个需求,我们的第一反应是“天哪,鬼知道项目中有多少地方引用了ImageLoader库,我们要改多少代码,万一改代码导致其他bug怎么办”。问题是我们应该如何避免这种“一根头发牵一发而动全身”的尴尬局面。好吧,我们先来看看我们平时在项目中是如何引用图片加载库的。before.png上图是我们大多数人所做的。那么如何才能换一个第三方加载库,同时保持这四个引用类不变呢。看看我们改版后的参考流程图after.png。从上图中可以看出,我们通过一个中间层引用了“第三方图片加载库”。这样做的好处是无论你把第三方图片加载库改成Picasso还是Glide,我们改的只是中间层,不需要改一行代码。如果你当时是这样设计的,当老板让你把Universal-Image-Loader换成Picasso的时候,你一行代码都不用改,只需要扩展一个类就可以了。好了,废话不多说,让我们看看代码是如何设计的。这里我使用代理模式来实现代码和图片加载库的隔离。先抽象一个ImageLoader接口***图片加载器功能接口;*添加或替换一个新的图像加载器来实现这个接口*/publicinterfaceImageLoader{/***InitImageLoader*/voidinit(Contextcontext);/***ShowImage**@paramimageUrl*@paramimageView*@paramdefaultImage*/voiddisplayImage(StringimageUrl,ImageViewimageView,intdefaultImage);}我们目前在项目中使用UniversalImageLoader来显示图片,所以我们将构建一个UniversalImageLoader类来实现上面的接口publicclassUniversalImageLoaderimplementsImageLoader{privatefinallongdiscCacheLimitTime=CacheLimitTime=0*24*15L;privatecom.nostra13。universalimageloader.core.ImageLoaderimageLoader=com.nostra13.universalimageloader.core.ImageLoader.getInstance();@Overridepublicvoidinit(Contextcontext){if(!imageLoader.isInited()){ImageLoaderConfigurationconfig=newImageLoaderConfigurationBuilder(context).threadPriority(线程.NORM_PRIORITY).denyCacheImageMultipleSizesInMemory().memoryCache(newWeakMemoryCache()).memoryCacheSize((2*1024*1024)).memoryCacheSizePercentage(13).discCacheDisFileNameGenerator(NewMatord5FileName)iskCache(StorageUtils.getCacheDirectory(context),discCacheLimitTime)).tasksProcessingOrder(QueueProcessingType.LIFO).build();com.nostra13.universalimageloader.core.ImageLoader.getInstance().init(config);}}@OverridepublicvoiddisplayImage(Stringuri,ImageViewimg,intdefault_pic){DisplayImageOptions=newDisplayImageOptions.Builder().showImageOnLoading(default_pic).showImageForEmptyUri(default_pic).showImageOnFail(default_pic).cacheInMemory(true).cacheOnDisc(true).bitmapConfig(Bitmap.Config.displayermap).RGB_6()).build();imageLoader.displayImage(uri,img,options);}接下来我们写一个代理类来帮助我们实现图片加载的任务/***图片加载代理类,所有的图片操作都通过这个代理要实现的类;*如果要更改图片加载框,只需要在该类中替换相应的图片加载框即可,客户端引用的所有图片操作不需要修改*/publicclassImageLoaderProxyimplementsImageLoader{privateImageLoaderimageLoader;//代理对象privatestaticImageLoaderProxyimageLoaderProxy;publicstaticImageLoaderProxygetInstance(){if(imageLoaderProxy==null){imageLoaderProxy=newImageLoaderProxy();}返回imageLoaderProxy;}publicImageLoaderProxy(){imageLoader=newUniversalImageLoader();}@Overridepublicvoidinit(Contextcontext){imageLoader.init(context);}@OverridepublicvoiddisplayImage(StringimageUrl,ImageViewimageView,intdefaultImage){imageLoader.displayImage(imageUrl,imageView,defaultImage);这样客户端所有需要显示图片的地方只需要调用代理类的图片显示方法即可。class然后替换这行代码imageLoaderProxy=newUniversalImageLoader();在代理类中使用imageLoaderProxy=newPicassoImageLoader()。不如我们改一行代码,换一个图片加载库方便。