Glide和Picasso是目前Android开发中很流行的图片加载库,Glide库和Picasso库也有极大的相似性,这篇文章就通过对比的方式描述一下这个两个功能强大的优秀库的使用。

一、简介:

1、picasso
picasso是Square公司开源的一个Android图形缓存库,不仅实现了图片异步加载的功能,还解决了android中加载图片时需要解决的一些常见问题:

  • 在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题;
  • 使用复杂的图片压缩转换来尽可能的减少内存消耗;
  • 自带内存和硬盘二级缓存功能。

2、 Glide
Glide 是一个高效、开源、 Android设备上的媒体管理框架,Glide具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个,一个是实现平滑的图片列表滚动效果(滚动流畅),另一个是支持远程图片的获取、大小调整和展示。有以下特点:

  • GIF动画的解码:通过调用Glide.with(context).load(“图片路径“方法,GIF动画图片可以自动显示为动画效果。如果想有更多的控制,还可以使用Glide.with(context).load(“图片路径“).asBitmap()方法加载静态图片,使用Glide.with(context).load(“图片路径“).asGif()方法加载动画图片。
  • 本地视频剧照的解码:通过调用Glide.with(context).load(“图片路径“)方法,Glide能够支持Android设备中的所有视频剧照的加载和展示。
  • 缩略图的支持:为了减少在同一个view组件里同时加载多张图片的时间,可以调Glide.with(context).load(“图片路径“).thumbnail(“缩略比例“).into(“view组件“)方法加载一个缩略图,还可以控制thumbnail()中的参数的大小,以控制显示不同比例大小的缩略图。
  • Activity生命周期的集成:当Activity暂停和重启时,Glide能够做到智能的暂停和重新开始请求,并且当Android设备的连接状态变化时,所有失败的请求能够自动重新请求。
  • 转码的支持:Glide的toBytes() 和transcode() 两个方法可以用来获取、解码和变换背景图片,并且transcode() 方法还能够改变图片的样式。
  • 动画的支持:新增支持图片的淡入淡出动画效果(调用crossFade()方法)和查看动画的属性的功能。
  • OkHttp和Volley的支持:默认选择HttpUrlConnection作为网络协议栈,还可以选择OkHttp和Volley作为网络协议栈。
  • 其他功能:如在图片加载过程中,使用Drawables对象作为占位符、图片请求的优化、图片的宽度和高度可重新设定、缩略图和原图的缓存等功能。
    3、总结:
    Picasso所能实现的功能,Glide都能做,只是所需的设置不同。但是Picasso体积比起Glide小太多如果项目中网络请求本身用的就是okhttp或者retrofit(本质还是okhttp),那么建议用Picasso,体积会小很多。Glide的好处是大型的图片流,比如gif、Video,如果做美拍这种视频类应用,建议使用。

二、具体应用:

Picasso和Glide都在jcenter上,使用时在项目中添加依赖

1、glide的应用:

TransitionOptions决定图片加载完成如何从占位符图片(或者之前的图片)过渡,有三种TransitionOptions
1. 添加依赖库:

compile 'com.github.bumptech.glide:glide:3.8.0'compile 'com.android.support:support-v4:25.4.0'

2.添加依赖后,开始使用

   /**     * Glide加载网络图片     *     * @param imgUrl 图片地址     */    private void GlideShowImg(String imgUrl) {        Glide.with(this) //this 是上下文 activity/fragment                .load(imgUrl)//根据地址下载图片                .listener(setRequestListner())//设置监听                .override(600, 600)//Glide加载图片大小是自动调整的,他根据ImageView的尺寸自动调整加载的图片大小,                // 并且缓存的时候也是按图片大小缓存,每种尺寸都会保留一份缓存,如果图片不会自动适配到 ImageView,调用 override(horizontalSize, verticalSize) 。                // 这将在图片显示到 ImageView之前重新改变图片大小//                .dontAnimate()//不使用glide默认的渐入渐出的动画                .fitCenter()//缩放//                .transform(new GlideRoundTransform(this,20))//显示圆角图片//                .transform(new GlideRotateTransform(this,90))//显示旋转后的图片//                .transform(new GlideCircleTransform(this))//显示圆形图片//                .transform(new GlideRoundTransform(this,20),new GlideRotateTransform(this,90))//圆角且旋转后的显示//                .animate(R.anim.sacle_rotate_anim)//以自定义动画的方式显示                .placeholder(R.mipmap.icon_default)//默认显示图片                .error(R.mipmap.icon_error)//图片加载错误显示的图片                .into(imageView);//显示    }
    public RequestListener setRequestListner() {        //设置错误监听        RequestListener errorListener = new RequestListener() {            @Override            public boolean onException(Exception e, String model, Target target, boolean isFirstResource) {                //图片加载异常的回调                Log.e("onException", e.toString() + "  model:" + model + " isFirstResource: " + isFirstResource);                imageView.setImageResource(R.mipmap.icon_error);                return false;            }            @Override            public boolean onResourceReady(GlideDrawable resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) {                //图片加载成功的回调                Log.e("onResourceReady", "isFromMemoryCache:" + isFromMemoryCache + "  model:" + model + " isFirstResource: " + isFirstResource);                return false;            }        };        return errorListener;    }

代码的注释都很明确,再详细说明一下:
1. Glide可以加载以下五种图片资源,图片的加载以String 型的url为例,一下一句代码就可以实现:

DrawableTypeRequest load(String string)DrawableTypeRequest load(Uri uri)DrawableTypeRequest load(File file)DrawableTypeRequest load(Integer resourceId)DrawableTypeRequest load(URL url)Glide.with(context).load(imageUrl).into(imageView);

2.当加载图片失败时,通过error(Drawable drawable)方法设置加载失败后的图片显示:

Glide.with(context).load(imageUrl).error(R.mipmap.ic_launcher).into(imageView);

3.当图片加载失败后,为了方便找失败的原因可以设置监听事件,通过事件中的回调方法快速准确的定位问题。

Glide.with(context).load(imageUrl)..listener(RequestListener).error(R.mipmap.ic_launcher).into(imageView);

3.1. 网络权限原因导致的错误

firstRequestSuccess.png
3.2.请求超时导致的错误error_msg.png
3.3第一次请求成功后的监听firstRequestSuccess.png
3.4第二次请求成功secondSuccess.png从这张截图可以看出第一次请求是直接从网络拿到的图片,当请求成功以后就放在缓存中,下次加载就直接从缓存中取图片。
4.Glide缓存

Glide.with( context ).load(imageUrl).skipMemoryCache(true).into(imageView);//跳过内存缓存Glide.with( context ).load(imageUrl).diskCacheStrategy(DiskCacheStrategy.NONE).into( imageView);//跳过硬盘缓存

DiskCacheStrategy.NONE 什么都不缓存
DiskCacheStrategy.SOURCE 仅仅只缓存原来的全分辨率的图像
DiskCacheStrategy.RESULT 仅仅缓存最终的图像,即降低分辨率后的或者是转换后的(默认行为)
DiskCacheStrategy.ALL 缓存所有版本的图像
想要指定缓存目录,新建一个类继承GlideModule,实现他的applyOptions(Context context, GlideBuilder builder)方法中写指定的目录及缓存大小

public class CustomCachingGlideModule implements GlideModule {    @Override    public void applyOptions(Context context, GlideBuilder builder) {        // 设置磁盘缓存为100M,缓存在内部缓存目录        int cacheSize100MegaBytes = 104857600;        builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "glide_cache", cacheSize100MegaBytes));        //builder.setDiskCache(        //new ExternalCacheDiskCacheFactory(context, "glide_cache",cacheSize100MegaBytes));        // 20%大的内存缓存作为 Glide 的默认值        MemorySizeCalculator calculator = new MemorySizeCalculator(context);        int defaultMemoryCacheSize = calculator.getMemoryCacheSize();        int defaultBitmapPoolSize = calculator.getBitmapPoolSize();        int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);        int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);        builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize));        builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize));    }    @Override    public void registerComponents(Context context, Glide glide) {        // nothing to do here    }}

然后再使用Glide加载图片的时候加上缓存策略(eg: .diskCacheStrategy(DiskCacheStrategy.ALL// 缓存所有尺寸的图片)就可以在你设置的缓存目录中看到缓存的图片了。
5. 图片的缩放,centerCrop()fitCenter()
5.1 使用centerCrop是利用图片图填充ImageView设置的大小,如果ImageView的Height是match_parent则图片就会被拉伸填充

Glide.with(context).load(imageUrl).centerCrop().into(imageView);

5.2 使用fitCenter即缩放图像让图像都测量出来等于或小于 ImageView 的边界范围,该图像将会完全显示,但可能不会填满整个ImageView。

Glide.with(context).load(imageUrl).fitCenter().into(imageView);

6.自定义图片转换 transform
自定义转换,实现一些特殊的展示样式,比如显示为圆角或者圆形。可以通过创建一个新的类实现了 Transformation 接口,然后在transform()里实现过如果我们只是做图片的转换可以直接用Glide封装好的BitmapTransformation抽象类。图像转换操作只需要在transform里实现。getId() 方法描述了这个转换的唯一标识符。Glide 使用该键作为缓存系统的一部分,为了避免意外的问题,你要确保它是唯一的 。
下面看是圆角、圆形跟选转的示例代码:
6.1 圆形的代码示例

public class GlideCircleTransform extends BitmapTransformation {    public GlideCircleTransform(Context context) {        super(context);    }    @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {        return circleCrop(pool, toTransform);    }    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {        if (source == null) return null;        int size = Math.min(source.getWidth(), source.getHeight());        int x = (source.getWidth() - size) / 2;        int y = (source.getHeight() - size) / 2;        // TODO this could be acquired from the pool too        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);        if (result == null) {            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);        }        Canvas canvas = new Canvas(result);        Paint paint = new Paint();        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));        paint.setAntiAlias(true);        float r = size / 2f;        canvas.drawCircle(r, r, r, paint);        return result;    }    @Override public String getId() {        return getClass().getName();    }

6.2圆角的代码示例:

/** * 将图像转换为四个角有弧度的图像 */public class GlideRoundTransform extends BitmapTransformation {    private float radius = 0f;    public GlideRoundTransform(Context context) {        this(context, 100);    }    public GlideRoundTransform(Context context, int dp) {        super(context);        this.radius = Resources.getSystem().getDisplayMetrics().density * dp;    }    @Override    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {        return roundCrop(pool, toTransform);    }    private Bitmap roundCrop(BitmapPool pool, Bitmap source) {        if (source == null) return null;        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);        if (result == null) {            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);        }        Canvas canvas = new Canvas(result);        Paint paint = new Paint();        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));        paint.setAntiAlias(true);        RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());        canvas.drawRoundRect(rectF, radius, radius, paint);        Log.e("11aa", radius + "");        return result;    }    @Override    public String getId() {        return getClass().getName() + Math.round(radius);    }}

6.3旋转示例代码:

/** * 将图像做旋转操作 */public class GlideRotateTransform extends BitmapTransformation {    private float rotateAngle = 0f;    public GlideRotateTransform(Context context) {        this(context, 90);    }    public GlideRotateTransform(Context context, float rotateAngle) {        super(context);        this.rotateAngle = rotateAngle;    }    @Override    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {        Matrix matrix = new Matrix();        matrix.postRotate(rotateAngle);        return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);    }    @Override    public String getId() {        return getClass().getName() + rotateAngle;    }}

需要注意的一点transform()如果多次调用,后面的效果会覆盖前面的,所以不要多次调用。若需要实现组合效果,transform可以接受任意长度的参数,所以可以组合使用:

 public DrawableRequestBuilder transform(BitmapTransformation... transformations) {        return bitmapTransform(transformations);    }//应用: .transform(new GlideRoundTransform(this,20),new GlideRotateTransform(this,90))//圆角且旋转后的显示

Glide4.0特性及使用

下面说说Glide4.0的新的使用方式,在Glide4.0版及以上版本,Glide使用了annotation processor来生成API,允许应用修改RequestBuilderRequestOptions和任意的包含在单一流式API库中的方法。这是V4的特性,运用注解后使用起来更方便,Glidev4中的Glide.with().load()后没有之前版本的fitCenterplaceholder这样的方法,但是GlideApp有,可以直接在builder中使用。GlideApp可以代替之前版本的Glide开头。

  • 相关依赖添加如下:
dependencies {  compile 'com.github.bumptech.glide:glide:4.3.1'  annotationProcessor 'com.github.bumptech.glide:compiler:4.3.1'}
  • 相关类介绍:

1 .GlideModule

在项目中实现 AppGlideModule,注意这个必须有注解,否则添加的方法失效。如果是library就实现LibraryGlideModule

@GlideModulepublic class CustomGlideModule extends AppGlideModule {}

2. GlideExtension

也可以添加新的方法、修改已有的方法或者添加对其他类型格式的支持,只要在扩展中使用加了注解的静态方法。
eg:GlideOption用来添加自定义的方法:
先新建一个CustomGlideExtension类两个方法:

@GlideExtensionpublic class CustomGlideExtension {    //缩略图的最小尺寸,单位:px    private static final int MINI_THUMB_SIZE = 100;    /**     * 将构造方法设为私有,作为工具类使用     */    private CustomGlideExtension() {    }    /**     * 1.自己新增的方法的第一个参数必须是RequestOptions options     * 2.方法必须是静态的     * @param options     */    @GlideOption    public static void miniThumb(RequestOptions options) {        options                .fitCenter()                .override(MINI_THUMB_SIZE);    }}

编译工程,打开build目录中的GlideOptions,可以看见自动生成了

public class GlideOptions extends RequestOptions {  /**   * @see CustomGlideExtension#miniThumb(RequestOptions)   */  public GlideOptions miniThumb() {    CustomGlideExtension.miniThumb(this);    return this;  }  /**   * @see CustomGlideExtension#miniThumb(RequestOptions)   */  public static GlideOptions miniThumbOf() {    return new GlideOptions().miniThumb();  }  ...}

引用添加的自定义方法:

GlideApp.with(fragment)        .load(url)        .miniThumb(thumbnailSize)        .into(imageView);

GlideType用来支持新的格式。在刚才的 CustomGlideExtension类中加上:

@GlideExtensionpublic class CustomGlideExtension {    private static final RequestOptions DECODE_TYPE_GIF = GlideOptions.decodeTypeOf(GifDrawable.class).lock();    @GlideType(GifDrawable.class)    public static void asGIF(RequestBuilder requestBuilder) {        requestBuilder                .transition(new DrawableTransitionOptions())                .apply(DECODE_TYPE_GIF);    }}

编译工程,打开build目录中的GlideRequests,可以看见自动生成了一个方法:

public class GlideRequests extends RequestManager {  /**   * @see CustomGlideExtension#asGIF(RequestBuilder)   */  public GlideRequest asGIF() {    GlideRequest requestBuilder = this.as(GifDrawable.class);    CustomGlideExtension.asGIF(requestBuilder);    return requestBuilder;  }}

引用自定义的GlideType

GlideApp.with(fragment)        .asGIF()        .load(url)        .into(imageView);

3. Options

Glide中的大多请求参数都可以通过RequestOptions类和apply()方法来设置。Placeholders 占位符
Transformations 变换、Caching Strategies缓存策略、组件特定参数:编码质量,解码参数等。
eg:要将图片的显示方式设为CenterCrop

import static com.bumptech.glide.request.RequestOptions.centerCropTransform;Glide.with(fragment)    .load(url)    .apply(centerCropTransform(context))    .into(imageView);

但是其实完全可以在layout文件中设置ImageViewandroid:scaleType="centerCrop"Glide会自动根据这个属性设置图片的显示方式。
apply方法可以调用多次,但是如果两次apply存在冲突的设置,会以最后一次为准。

4. TransitionOptions

TransitionOptions决定图片加载完成如何从占位符图片(或者之前的图片)过渡,有三种TransitionOptions

  1. GenericTransitionOptions 通用型
  2. DrawableTransitionOptions
  3. BitmapTransitionOptions

如果要使用自定义的动画,可以使用GenericTransitionOptions.with(int viewAnimationId)或者BitmapTransitionOptions.withCrossFade(int animationId, int duration)或者DrawableTransitionOptions.withCrossFade(int animationId, int duration)

Glide.with(fragment)    .load(url)    .transition(DrawableTransitionOptions.withCrossFade())    .into(view);

注意

TransitionOptions是和你要加载的资源的类型绑定的,也就是说,如果你请求一张位图(Bitmap),你就需要使用BitmapTransitionOptions,而不是DrawableTransitionOptions因此,你请求的这张位图,你需要用简单的淡入,而不能用交叉淡入DrawableTransitionOptions.withCrossFade()
如果既不是Bitmap也不是Drawable可以使用GenericTransitionOptions

5. RequestBuilder

作用:

  1. 指定加载类型。asBitmap()asGif()asDrawable()asFile()
  2. 指定要加载url/model。
  3. 指定要加载到那个View。
  4. 指定要应用的RequestOption
  5. 指定要应用的TransitionOption
  6. 指定要加载的缩略图

5.1 初始化RequestBuild

RequestBuilder requestBuilder = Glide.with(fragment);

默认得到一个Drawable RequestBuilder,如果要指定类型为Bitmap,可以这样写:

RequestBuilder requestBuilder = Glide.with(fragment).asBitmap();

5.2 应用 RequestOptions

RequestBuilder requestBuilder = Glide.with(fragment);requestBuilder.apply(requestOptions);requestBuilder.transition(transitionOptions);

5.3 RequestBuilder也可以重复使用:

RequestBuilder requestBuilder = Glide.with(fragment)                                               .asDrawable()                                               .apply(requestOptions);        for (int i = 0; i < numViews; i++) {           ImageView view = viewGroup.getChildAt(i);           String url = urls.get(i);           requestBuilder.load(url).into(view);        }

6.Transformations·

Glide会自动读取ImageView的缩放类型,所以一般在layout文件指定scaleType即可。Glide支持在java代码中设置这些缩放类型:

  1. CenterCrop 缩放宽和高都到达View的边界,有一个参数在边界上,另一个参数可能在边界上,也可能超过边界
  2. CenterInside 如果宽和高都在View的边界内,那就不缩放,否则缩放宽和高都进入View的边界,有一个参数在边界上,另一个参数可能在边界上,也可能在边界内
  3. CircleCrop 圆形且结合了CenterCrop的特性
  4. FitCenter 缩放宽和高都进入View的边界,有一个参数在边界上,另一个参数可能在边界上,也可能在边界内
  5. RoundedCorners 圆角

有三种用法:

6.1 使用RequestOptions

RequestOptions options = new RequestOptions();options.centerCrop();Glide.with(fragment)     .load(url)     .apply(options)     .into(imageView);

6.2 使用RequestOptions中的transform方法

Glide.with(fragment)     .load(url)     .apply(RequestOptions.fitCenterTransform())     .into(imageView);

6.3 V4特性

GlideApp.with(fragment)        .load(url)        .fitCenter()        .into(imageView);

6.4 多个变换

Glide.with(fragment)     .load(url)     .transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation())     .into(imageView);

picasso的应用:

1. 首先也是添加依赖:

compile 'com.squareup.picasso:picasso:2.5.2'

2. 以网络图片加载为例介绍下picasso的基本用法:

/**     * @param imgUrl 用picasso加载图片     */    private void picassoShowImg(String imgUrl) {        Picasso.with(this)                .load(imgUrl)                .placeholder(R.mipmap.icon_default)//加载过程中的图片显示//                .noPlaceholder()//加载过程中不显示默认图片//                .noFade()//Picasso的默认图片加载方式有一个淡入的效果,如果调用了noFade(),加载的图片将直接显示在ImageView上(根据需求添加此代码)                .error(R.mipmap.icon_error)                .resize(400, 400)                .onlyScaleDown()//如果我们调用了resize(x,y)方法的话,Picasso一般会重新计算以改变图片的加载质量,                // 比如一张小图变成一张大图进行展示的时候,但是如果原图是比重新resize的新图规格大的时候,就可以调用onlyScaleDown()来直接进行展示而不再重新计算                .centerInside()//图片会被完整的展示,可能图片不会填充满ImageView`,也有可能会被拉伸或者挤压//                .centerCrop()//图片会被剪切,但是图片质量看着没有什么区别//                .fit()//对图片的大小及ImageView进行测量,计算出最佳的大小及最佳的图片质量来进行图片展示,减少内存,并对视图没有影响;                .priority(Picasso.Priority.HIGH)//图片加载的优先级,分为HIGH, MEDIUM, 和 LOW,所有的加载默认优先级为MEDIUM;                .into(imageView);    }

2.1 load()还有以下几种重载

1、load(Uri uri)
2、load(File file)
3、load(int resourceId)

3.加载过程中的图片显示:

Picasso.with(this)                .load(imgUrl)                .placeholder(R.mipmap.icon_default)//加载过程中的图片显示                .into(imageView);

4、加载失败后错误图片显示:

Picasso.with(this)                .load(imgUrl)                .error(R.mipmap.icon_error)//加载失败错误图片显示                .into(imageView);

5、图片填充样式
5.1 centerInside()按比例裁减图片,图片可以完全显示,但如果图片比View小,则无法充满整个View,必须与resize()方法同时使用。

Picasso.with(this)                .load(imgUrl)                .resize(320, 640)                .centerInside()                .into(imageView);

5.2 centerCrop()按比例裁减图片,使其居中显示,充满View,会造成图片显示不全,必须与resize()方法同时使用。

Picasso.with(this)                .load(imgUrl)                .resize(320, 640)                .centerCrop()                .into(imageView);

5.3 fit()该属性会根据Image View的大小充满整个View,不考虑比例,可能造成图片的拉伸或者缩小。

Picasso.with(this)                .load(imgUrl)                .resize(320, 640)                .centerCrop()                .into(imageView);

5.4 onlyScaleDown()这里面使用的测试图片的大小是12401563,如果resize的宽高大于图片的原始宽高,则resize不起作用,采用图片原始宽高显示。

Picasso.with(this)                .load(imgUrl)                .resize(320, 640)                .onlyScaleDown()                .into(imageView);

6. noFade()取消图片的过渡显示效果。

Picasso.with(this)                .load(imgUrl)                .resize(320, 640)                .noFade()                .into(imageView);

7rotate()图片旋转。

Picasso.with(this)                .load(imgUrl)                .rotate(45)//以(0,0)为中心顺时针旋转45度              //  .rotate(45,30,30)//以(30,30)为中心顺时针旋转45度                .into(imageView);

picasso_rotate_45.png
8、priority()优先级

Picasso.with(this)                .load(imgUrl)                .priority(Picasso.Priority.HIGH)//分为HIGH, NORMAL, 和 LOW,默认优先级为NORMAL;                .into(imageView);

9、缓存策略

Picasso.with(this)                .load(imgUrl)                .priority(Picasso.Priority.HIGH)//分为HIGH, NORMAL, 和 LOW,默认优先级为NORMAL;                .into(imageView);

更多相关文章

  1. 彻底解决Android(安卓)拍照 内存溢出 Out of Memory的问题
  2. android,微信,人人,微博开机加载一幅图片,再跳转到主应用的实现
  3. 关于Android加载状态视图切换
  4. Android中进行图像压缩和缩放
  5. Android(安卓)nomedia 避免图片等资源泄露在系统图库当中
  6. 【构建Android缓存模块】(一)吐槽与原理分析
  7. (Android) 单击屏幕事件和滑动屏幕事件共存的解决方案
  8. Android中适配器getView()原理和ListView加载多个Item.
  9. Android内存优化总结&实践

随机推荐

  1. Android(安卓)Studio开发常见问题及解决
  2. Android App 结束运行后重启
  3. Androidx和Android(安卓)support库的冲突
  4. Android(安卓)可任意拖动的悬浮窗(类似悬
  5. 【Java】java和android网络编程 - 对byte
  6. Android进度条样式
  7. Android 之retrofit2 之 @body上传服务器
  8. 16个最热门的 Android Apps 推荐下载
  9. Android 之listview \gridview 属性设置
  10. Android点击返回按钮两次退出系统