框架设计过程中对于对于架构要求高内聚低耦合,图片加载框架中引
入三方框架提示开发效率,对于技术选型后的方案可能后面需求的变更原三方
sdk无法满足当前业务需求,故而需要更换原有sdk,为了将更改降到最低,所
有前面设计图片加载框架时要考虑当前这个风险点
使用设计模式来进一步解耦代码耦合度,来解决隔离风险点的目的,
即定义接口层业务依赖抽象即当前接口,具体实现有不同三方sdk完成。
因为业务依赖的是接口层对应后期代码维护更改量会控制在最小,对于原软件
稳定性影响也会极小达到更换图片加载框架的目的。
GlideImageLoader/FrscoImageLoader/PicassoImageLoader
* @Author : yaotianxue * @Time : On 2023/5/22 16:50 * @Description : GlideImageLoader class GlideImageLoader : IImageLoader { override fun loadFileIntoImageView ( context : Context , file : File , target : ImageView , config : ImageOptions , loadImageView ( context , file , target , config ) override fun loadUrlIntoImageView ( context : Context , url : String , target : ImageView , config : ImageOptions , loadImageView ( context , url , target , config ) override fun loadResourceIntoImageView ( context : Context , source : Int , target : ImageView , config : ImageOptions , loadImageView ( context , source , target , config ) override fun loadUriIntoImageView ( context : Context , uri : Uri , target : ImageView , config : ImageOptions , loadImageView ( context , uri , target , config ) override fun loadByteArrayIntoImageView ( context : Context , bytes : Array < Byte > , target : ImageView , config : ImageOptions , loadImageView ( context , bytes , target , config ) private fun loadImageView ( context : Context , source : Any , target : ImageView , config : ImageOptions , //内存泄漏:该回收的资源无法被回收掉 context是activity,当页面销毁该回收activity,但是由于Glide引用当前activity、 导致activity无法回收 //解决方案1:使用弱应用 //解决方案2:activity传入上下文不要传this,传入application var weakReference = WeakReference < Context > ( context ) //弱引用 if ( weakReference . get ( ) == null ) { return var builder = GlideApp . with ( context ) . load ( source ) setBuilderOptions ( builder , config ) builder . into ( target ) * 设置图片参数 private fun setBuilderOptions ( builder : GlideRequest < Drawable > , config : ImageOptions ) { config . let { var options = RequestOptions ( ) if ( config . placeImage != 0 ) { options . placeholder ( config . placeImage ) if ( config . errorImage != 0 ) { options . error ( config . errorImage ) config . imageSize . let { if ( config . imageSize . size != 2 ) { throw IllegalArgumentException ( "please set imageSize length size is 2" ) options . override ( config . imageSize [ 0 ] , config . imageSize [ 1 ] ) if ( config . skipDiskCache ) options . diskCacheStrategy ( DiskCacheStrategy . NONE ) if ( config . skipMemoryCache ) options . skipMemoryCache ( true ) builder . apply ( options )ImageUtils.loadIageView(this,"",iv)
三.Glide配置
1.依赖:
config.gradle配置:
//Glide // Glide集成OkHttp时需要使用的库,库已经将需要适配Okhhtp的大部分代码封装,注意如果之前已经使用了okhttp依赖注释掉 libIntegration = 'com.github.bumptech.glide:okhttp3-integration:4.13.0' libGlide = 'com.github.bumptech.glide:glide:4.13.0' libGlideCompiler = 'com.github.bumptech.glide:compiler:4.13.0'//Glide注解处理器的依赖
library-base封装网络
//glide图片框架 api libGlide api libIntegration kapt libGlideCompiler
项目结构:
2.缓存配置:
* @Author : yaotianxue * @Time : On 2023/5/22 17:03 * @Description : MyGlideModule 配置glide缓存 @GlideModule class CacheGlideModule:AppGlideModule() { override fun applyOptions(context: Context, builder: GlideBuilder) { //super.applyOptions(context, builder) //设置内存缓存大小:根据机器自动计算 // var memorySizeCalculator = MemorySizeCalculator.Builder(context).build() // builder.setMemoryCache(LruResourceCache(memorySizeCalculator.memoryCacheSize.toLong())) //设置内存缓存大小:10M builder.setMemoryCache(LruResourceCache(10*1024*1024)) //设置磁盘缓存大小:500M 默认250M 设置磁盘缓存文件夹名称 "my_image" 默认 "image_manager_disk_cache" builder.setDiskCache(InternalCacheDiskCacheFactory(context,"my_image",500*1024*1024))//修改磁盘缓存的文件夹和磁盘大小3.网络配置:glide默认使用httpUrlConnection完成网络请求,可以改成okhttp
* @Author : yaotianxue * @Time : On 2023/5/22 17:07 * @Description : OkhttpGlideModule:配置okhttp认证所有证书,可以认证自定义ca证书 @GlideModule class OkhttpGlideModule:LibraryGlideModule() { override fun registerComponents(context: Context, glide: Glide, registry: Registry) { // super.registerComponents(context, glide, registry) var client = OkHttpClient.Builder() .sslSocketFactory(sSLSocketFactory,trustManager) .build() registry.replace(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(client)) /** 获取一个SSLSocketFactory */ val sSLSocketFactory: SSLSocketFactory get() = try { val sslContext = SSLContext.getInstance("SSL") sslContext.init(null, arrayOf(trustManager), SecureRandom()) sslContext.socketFactory } catch (e: Exception) { throw RuntimeException(e) /** 获取一个忽略证书的X509TrustManager */ val trustManager: X509TrustManager get() = object : X509TrustManager { override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) { } override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) { } override fun getAcceptedIssuers(): Array<X509Certificate> { return arrayOf() }四.Bitmap三级缓存二次采样
五.长图大图处理
https://www.jianshu.com/p/5ec13b295dd0
import android.app.appsearch.GetByDocumentIdRequest; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android. graphics.BitmapRegionDecoder; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.InputDevice; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; * @Author : yaotianxue * @Time : On 2023/5/22 19:47 * @Description : LargeImageView public class LargeImageView extends View implements GestureDetector.OnGestureListener { private BitmapRegionDecoder mDecoder; //绘制的区域 private volatile Rect mRect = new Rect(); private int mScaledTouchSlop; //分别记录上次的滑动的坐标 private int mLastX = 0; private int mLastY = 0; //图片的宽度和高度 private int mImageWidth,mImageHeight; //手势控制器 private GestureDetector mGestureDetector; //Bitmap工厂参数配置 private BitmapFactory.Options mOptions; private String name; public void setName(String name) { this.name = name; public LargeImageView(Context context) { super(context); init(context,null); public LargeImageView(Context context, AttributeSet attrs) { super(context, attrs); init(context,attrs); public LargeImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context,attrs); public LargeImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context,attrs); private void init(Context context, AttributeSet attrs) { //设置图片参数,如果对图片要求高采用ARGB_8888 mOptions = new BitmapFactory.Options(); mOptions.inPreferredConfig = Bitmap.Config.RGB_565; mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); Log.d("ytx", "init: "+mScaledTouchSlop); //初始化手势控制器 mGestureDetector = new GestureDetector(context,this); InputStream inputStream = null; try { inputStream = context.getResources().getAssets().open("demo.jpg"); //初始化BitmapRegionDecoder,并用他显示图片 mDecoder = BitmapRegionDecoder.newInstance(inputStream,false); //设置为true只采取图片的宽度和高度,不加载进内存 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(inputStream,null,options); mImageHeight = options.outHeight; mImageWidth = options.outWidth; } catch (IOException e) { e.printStackTrace(); }finally { if(inputStream != null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); //把触摸事件交给手势控制器处理 @Override public boolean onTouchEvent(MotionEvent event) { return mGestureDetector.onTouchEvent(event); @Override public boolean onDown(MotionEvent e) { mLastX = (int) e.getRawX(); mLastY = (int) e.getRawY(); return true; @Override public void onShowPress(MotionEvent e) { @Override public boolean onSingleTapUp(MotionEvent e) { return false; @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { int x = (int) e2.getRawX(); int y = (int) e2.getY(); move(x,y); return true; //移动的时候更新图片的显示的区域 private void move(int x, int y) { int deltaX = x - mLastX; int deltaY = y - mLastY; if(mImageWidth > getWidth()){ mRect.offset(-deltaX,0); if(mRect.right < mImageWidth){ mRect.right = mImageWidth; mRect.left = mImageWidth - getWidth(); if(mRect.left < 0){ mRect.left = 0; mRect.right = getRight(); invalidate(); if(mImageHeight > getHeight()){ mRect.offset(0,-deltaY); if(mRect.bottom > mImageHeight){ mRect.bottom = mImageHeight; mRect.top = mImageHeight - getHeight(); if(mRect.top < 0){ mRect.top = 0; mRect.bottom = getHeight(); invalidate(); mLastX = x; mLastY = y; @Override public void onLongPress(MotionEvent e) { mLastX = (int) e.getRawX(); mLastY = (int) e.getRawY(); @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int x = (int)e2.getRawX(); int y = (int) e2.getRawY(); move(x,y); return true; @Override protected void onDraw(Canvas canvas) { Bitmap bitmap = mDecoder.decodeRegion(mRect,mOptions); canvas.drawBitmap(bitmap,0,0,null); @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); int height = getMeasuredHeight(); int imageWidth = mImageWidth; int imageHeight = mImageHeight; mRect.left = imageWidth/2 - width/2; mRect.top = imageHeight/2 - height/2; mRect.right = mRect.left +width; mRect.bottom = mRect.top + height; 网络配置:glide默认使用httpUrlConnection完成网络请求,可以改成okhttp。sdk无法满足当前业务需求,故而需要更换原有sdk,为了将更改降到最低,所。入三方框架提示开发效率,对于技术选型后的方案可能后面需求的变更原三方。因为业务依赖的是接口层对应后期代码维护更改量会控制在最小,对于原软件。即定义接口层业务依赖抽象即当前接口,具体实现有不同三方sdk完成。框架设计过程中对于对于架构要求高内聚低耦合,图片加载框架中引。使用设计模式来进一步解耦代码耦合度,来解决隔离风险点的目的,前言:这一节里面我们将介绍Glide如何对图片进行压缩,这一点在加载图片较多或者加载的图片像素很高的程序里面至关重要1.Android图片显示相关知识这里会讲一下图片显示相关的基础知识,如果不关心的可以直接跳到第二点,不过建议是最好看一下1.1图片质量分类安卓图片显示的质量配置主要分为四种: ARGB_8888 :32位图,带透明度,每个像素占4个字节 ARGB_4444 :16位图,带透明度,每个等比例缩放图片在聊天列表中比较常见,而不是显示固定宽高的图片。最近对IM项目迁移到Androidx时,顺便升级了glide,发现glide等比例缩放图片出现bug(自定义ImageViewTarget实现图片缩放),第一次能正常加载,第二次无法正常等比例缩放。原来项目是使用glide 3.7.0,现在是使用gilde 4.11.0 (4.10.0开始支持AndroidX) 不同版本...项目中遇到,需要用户上传图片的场景。结果用户上传的、特别是拍摄后的图片,分辨率很大,长宽2000多3000甚至更高,一个图片5MB以上。 造成之后,从网络上加载这些图片,比较慢。 所以,不得不在上传前进行压缩后,再上传。