Android-图片框架之Glide实现图形验证码及实现分析

先上代码:
private void getImageCode(boolean isClear) {

    mPbLoading.setVisibility(ProgressBar.VISIBLE); //加载菊花圈
    mTxtErrorNotice.setVisibility(View.GONE);//显示图片加载失败或者错误的文字,如果没这个需求则直接用glide的展位图即可

    if (isClear) {

        ACache mCache = ACache.get(this.getContext());轻量级缓存框架 //https://github.com/yangfuhai/ASimpleCache
        Bitmap imagecode = mCache.getAsBitmap("imagecode");
        if (imagecode != null) {
            mImageCode.setImageBitmap(imagecode);
            mPbLoading.setVisibility(ProgressBar.GONE);
            return;
        }
    }

    if (mSimpleTarget == null) {
        mSimpleTarget = new SimpleTarget<Bitmap>() {
            @Override
            public void onResourceReady(@android.support.annotation.NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                mPbLoading.setVisibility(ProgressBar.GONE);
                mTxtErrorNotice.setVisibility(View.GONE);
                mImageCode.setVisibility(View.VISIBLE);
                mImageCode.setImageBitmap(resource);

                ACache mCache = ACache.get(this.getContext());轻量级缓存框架//https://github.com/yangfuhai/ASimpleCache
                mCache.put("imagecode", resource, 200);
            }

            @Override
            public void onLoadFailed(@Nullable Drawable errorDrawable) {
                super.onLoadFailed(errorDrawable);
                mPbLoading.setVisibility(ProgressBar.GONE);
                mTxtErrorNotice.setVisibility(View.VISIBLE);
                mImageCode.setVisibility(View.INVISIBLE);
            }
        };
    }

    String updateTime = String.valueOf(System.currentTimeMillis()); // 在需要重新获取更新的图片时调用
    GlideApp.with(this)
            .asBitmap()
            .load(UrlConstants.ImageCodeUrl)
            .signature(new ObjectKey(updateTime))
            .into(mSimpleTarget);

    Timber.tag("imagecode");
    Timber.e("getImageCode");
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >

    <ImageView
        android:layout_marginRight="@dimen/px5"
        android:layout_marginTop="@dimen/px10"
        android:id="@+id/imageview_cancel"
        android:layout_width="@dimen/px49"
        android:layout_height="@dimen/px49"
        android:layout_gravity="right"
        android:layout_marginBottom="@dimen/px10"
        android:src="@mipmap/image_app_upload_dialog_cancel"/>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_alert_bg"
        android:paddingBottom="@dimen/px20"
        android:paddingLeft="@dimen/px20"
        android:paddingRight="@dimen/px20"
        android:paddingTop="@dimen/px20"
        >

        <ImageView
            android:id="@+id/iv_image_code"
            android:layout_width="match_parent"
            android:layout_height="@dimen/px150"
            android:layout_marginLeft="@dimen/px20"
            android:layout_marginRight="@dimen/px20"/>

        <TextView
            android:id="@+id/txt_error_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="@dimen/px60"
            android:gravity="center"
            android:text="获取失败,点击重试"
            android:textSize="@dimen/font_24px"
            android:visibility="gone"
            tools:visibility="visible"/>

        <ProgressBar
            android:id="@+id/progress_wheel_load"
            style="?android:attr/progressBarStyleLarge"
            android:layout_width="@dimen/px50"
            android:layout_height="@dimen/px50"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="@dimen/px40"
            android:indeterminateBehavior="repeat"
            android:indeterminateDrawable="@drawable/shape_state_progress"
            android:indeterminateDuration="600"
            android:indeterminateOnly="true"
            android:visibility="visible"
            tools:visibility="visible"
            />

        <TextView
            android:id="@+id/txt_reset_image_code"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/iv_image_code"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="@dimen/px20"
            android:text="看不清楚?点击刷新"
            />

        <TextView
            android:visibility="gone"
            tools:visibility="visible"
            android:id="@+id/txt_error_input_notice"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/txt_reset_image_code"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="@dimen/px20"
            android:text="图形验证码错误,请重新输入!"
            android:textColor="@color/red"
            />

            <!--android:inputType="number"-->
        <EditText
            android:id="@+id/edit_image_code"
            android:layout_width="match_parent"
            android:layout_height="@dimen/px140"
            android:layout_below="@+id/txt_reset_image_code"
            android:background="@null"
            android:gravity="bottom|center_horizontal"
            android:hint="请输入图形验证码"
            android:digits="0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM"
            android:maxLength="5"
            android:paddingBottom="@dimen/px15"
            android:paddingLeft="@dimen/px20"
            android:paddingRight="@dimen/px20"
            android:textColorHint="#969696"
            android:textCursorDrawable="@drawable/shape_login_edittext_cursor_color"
            android:textSize="@dimen/font_32px"/>

        <View
            android:id="@+id/view_divider1"
            android:layout_width="match_parent"
            android:layout_height="@dimen/px1"
            android:layout_below="@+id/edit_image_code"
            android:layout_marginLeft="@dimen/px20"
            android:layout_marginRight="@dimen/px20"
            android:background="#e5e5e5"/>

        <Button
            android:id="@+id/bt_send_sms_code"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="@dimen/px230"
            android:layout_height="@dimen/px80"
            android:layout_below="@+id/view_divider1"
            android:layout_centerHorizontal="true"
            android:layout_marginLeft="@dimen/px20"
            android:layout_marginRight="@dimen/px20"
            android:layout_marginTop="@dimen/px20"
            android:background="@drawable/yeyout_def_btn_bg_selector"
            android:clickable="true"
            android:gravity="center"
            android:text="确定"
            android:textColor="#FFF"
            android:textSize="@dimen/font_32px"/>
    </RelativeLayout>
</LinearLayout>



以上我是使用Acache根据时间自己缓存了图片,其实是没有必要的,因为glide是自带这样效果的,直接设置自定义缓存key就好. 可以参考 Android-图片框架之Glide添加水印文字,模糊效果以及分析Glide 实现效果

自定义key需要实现Glide的key接口,同时确保正确地实现 equals()hashCode() 和 updateDiskCacheKey() 方法:

public class IntegerVersionSignature implements Key {
    private int currentVersion;

    public IntegerVersionSignature(int currentVersion) {
         this.currentVersion = currentVersion;
    }
   
    @Override
    public boolean equals(Object o) {
        if (o instanceof IntegerVersionSignature) {
            IntegerVersionSignature other = (IntegerVersionSignature) o;
            return currentVersion = other.currentVersion;
        }
        return false;
    }
 
    @Override
    public int hashCode() {
        return currentVersion;
    }

    //在此处做根据时间去判断更新现有的图片即可(根据时间戳判断并调用update方法)
    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
              messageDigest.update(ByteBuffer.allocate(Integer.SIZE).putInt(signature).array());
    }
}

因为懒癌发作,所以此处我没有给出根据时间去更新缓存的代码(后续再更新),只是给出了基本的复写方法哦。


分析原理:

Glide里的缓存

默认情况下,Glide 会在开始一个新的图片请求之前检查以下多级的缓存:

  1. 活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?
  2. 内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?
  3. 资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?
  4. 数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?

前两步检查图片是否在内存中,如果是则直接返回图片。后两步则检查图片是否在磁盘上,以便快速但异步地返回图片。

如果四个步骤都未能找到图片,则Glide会返回到原始资源以取回数据(原始文件,Uri, Url等)


Glide缓存键(Cache Keys)

在 Glide v4 里,所有缓存键都包含至少两个元素:

  1. 请求加载的 model(File, Url, Url)
  2. 一个可选的 签名(Signature)

另外,步骤1-3(活动资源,内存缓存,资源磁盘缓存)的缓存键还包含一些其他数据,包括:

  1. 宽度和高度
  2. 可选的变换(Transformation)
  3. 额外添加的任何 选项(Options)
  4. 请求的数据类型 (Bitmap, GIF, 或其他)

活动资源和内存缓存使用的键还和磁盘资源缓存略有不同,以适应内存 选项(Options),比如影响 Bitmap 配置的选项或其他解码时才会用到的参数。

为了生成磁盘缓存上的缓存键名称,以上的每个元素会被哈希化以创建一个单独的字符串键名,并在随后作为磁盘缓存上的文件名使用。


此处是Glide与其他开源图片框架不同的地方,它会根据手机屏幕,图片转换后的大小,显示的view的大小去获取和加载图片缓存


缓存的刷新

因为磁盘缓存使用的是哈希键,所以并没有一个比较好的方式来简单地删除某个特定url或文件路径对应的所有缓存文件。如果你只允许加载或缓存原始图片的话,问题可能会变得更简单,但因为Glide还会缓存缩略图和提供多种变换(transformation),它们中的任何一个都会导致在缓存中创建一个新的文件,而要跟踪和删除一个图片的所有版本无疑是困难的。

在实践中,使缓存文件无效的最佳方式是在内容发生变化时(url,uri,文件路径等)更改你的标识符。


定制缓存刷新策略

因为通常改变标识符比较困难或者根本不可能,所以Glide也提供了 签名 API 来混合(你可以控制的)额外数据到你的缓存键中。签名(signature)适用于媒体内容,也适用于你可以自行维护的一些版本元数据。

  • MediaStore 内容 - 对于媒体存储内容,你可以使用Glide的 MediaStoreSignature 类作为你的签名。MediaStoreSignature 允许你混入修改时间、MIME类型,以及item的方向到缓存键中。这三个属性能够可靠地捕获对图片的编辑和更新,这可以允许你缓存媒体存储的缩略图。
  • 文件 - 你可以使用 ObjectKey 来混入文件的修改日期。
  • Url - 尽管最好的让 url 失效的办法是让 server 保证在内容变更时对URL做出改变,你仍然可以使用 ObjectKey 来混入任意数据(比如版本号)。

将签名传入加载请求很简单:

GlideApp.with(yourFragment)
    .load(yourFileDataModel)
    .signature(new ObjectKey(yourVersionMetadata))
    .into(yourImageView);

媒体存储签名对于 MediaStore 数据来说也很直接:

GlideApp.with(fragment)
    .load(mediaStoreUri)
    .signature(new MediaStoreSignature(mimeType, dateModified, orientation))
    .into(view);

如果这些努力都无法奏效,您不能更改标识符,也不能跟踪任何合理的版本元数据的情况下,也可以使用 diskCacheStrategy() 和 DiskCacheStrategy.NONE来完全禁用磁盘缓存。


参考自Glide中文文档 https://muyangmin.github.io/glide-docs-cn/doc/caching.html


猜你喜欢

转载自blog.csdn.net/yang1349day/article/details/80307138