I read a blog that Glide has been upgraded to 4.0. I went to a sudden shock (although we used Imageloader for our project, I still like glide library). It’s time to know more about it.

Take a look at the official introduction, said that it has been Google internal use of the version, and is the most stable version, it is said that a few weeks to improve the bug will be issued official version,

Official introduction to the portal

Look at the official documentation, also quite —- confused, but after a struggle and N times of Google, has successfully upgraded from V3 to V4

All right, here we go

1. Project integration

- Project gradle Repository {mavenCentral() // JCenter () works as well because it repository from Maven Central}Copy the code
- app gradle/library/glide the compile 'com. Making. Bumptech. Glide: glide: 4.0.0 - RC0' / / the - the compile 'com. Android. Support: support - v4:25.3.1' / / this used in our custom annotations GlideModule annotationProcessor 'com. Making. Bumptech. Glide: the compiler: 4.0.0 - RC0' / / glide default is httpconnection, plus this is replaced by okhttp compile "Com. Making. Bumptech. Glide: okhttp3 - integration: 4.0.0 - RC0"Copy the code
Add confusion - keep public class * implements com. Bumptech. Glide. The module. The GlideModule - keep public class * extends com.bumptech.glide.AppGlideModule -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { **[] $VALUES; public *; } the GlideModule is a dule for the GlideModuleCopy the code

In the previous 3.x version, we configured our own GlideModule in the manifast file,just like the following

<meta-data
            android:name="com.xxx.xxx.xxx.xxx.MyGlideModule"
            android:value="GlideModule"/>
Copy the code

This time we first remove this configuration, because it is mentioned in the official introduction that the configuration in the manifast is slow in the initial glide reading (compared with V4 annotation).

How can I read the configuration information of my GlideModule? Don’t be urgent, and see the younger brother below say that

AppGlideModule< not GlideModule>

/** * Created by wangfei */ @GlideModule public class MyGlideModule extends AppGlideModule { @Override public void applyOptions(final Context context, GlideBuilder builder) {MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build(); // 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)); Int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes)); Int MAX_CACHE_SIZE = 100 * 1024 * 1024; String CACHE_FILE_NAME = "imgCache"; builder.setDiskCache(new ExternalCacheDiskCacheFactory(context,CACHE_FILE_NAME,MAX_CACHE_SIZE)); if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { String downloadDirectoryPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + CACHE_FILE_NAME; // path ---->sdcard/imgCache Builder. setDiskCache(new DiskLruCacheFactory(downloadDirectoryPath, MAX_CACHE_SIZE)); } else {// path ---->/sdcard/Android/data/<application package>/cache/imgCache Builder.setDiskCache (new ExternalCacheDiskCacheFactory(context, CACHE_FILE_NAME, MAX_CACHE_SIZE)); } } @Override public void registerComponents(Context context, Registry. Replace (glideurl.class, inputStream.class, new okHttpurLLoader.factory ());  } @override public Boolean isManifestParsingEnabled() {return manifestParsingEnabled (); }}Copy the code

Simple analysis

@ GlideModule this is the reason why we remove the manifast above, plus the annotations () will glide inside he generated a implementation class -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- location final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule { private final MyGlideModule appGlideModule; GeneratedAppGlideModuleImpl() { appGlideModule = new MyGlideModule(); if (Log.isLoggable("Glide", Log.DEBUG)) { Log.d("Glide", "Discovered AppGlideModule from annotation: com.wjf.fastdev.network.glide.MyGlideModule"); }} specific after you try, look at the source code here we mainly useCopy the code
This is where we change glide's default network request to okHTTPCopy the code
IsManifestParsingEnabled Because Glide V4 is V3 compatible it also reads GlideModule information from the manifast. However, we have the manifast The GlideModule is removed from the manifast. To ensure that glide is not read from the manifast, we need to initialize glide efficientlyCopy the code
<uses-permission: allows you to write to the SD card. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>Copy the code

Those of you who are careful may have noticed that we didn’t format the image

builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888)
Copy the code

This setting is no longer recommended for V4, but is described below


After this step, we can use our usual chain call

GlideApp.with(context) .asBitmap() .load(url) .placeholder(R.drawable.recommender_avatar_default) .error(R.drawable.recommender_avatar_default) .centerCrop() .into(imageview); Note that it is not Glide but GlideApp, which should be generated by annotations. I have not studied the specific, so I will add it laterCopy the code

3, the new API (RequestBuilder RequestOptions)

1,RequestBuilder

access

 RequestBuilder requestBuilder = GlideApp.with(context).load(url);
Copy the code

Configurable options

RequestBuilder requestBuilder = GlideApp.with(context).load(url); Listener(new RequestListener() {@override public Boolean onLoadFailed(@nullable GlideException)  e, Object model, Target target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Object resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; }}); // requestBuilder. Thumbnail (0.5f); // Load the image url requestBuilder.load("IMAGE_URL"); // Load the imageView object into requestBuilder. Into (imageView);Copy the code

And our common configuration is just like this

GlideApp.with(context).load(url).............. ; This is equivalent to creating a new requestBuilder, so I feel uselessCopy the code

2,RequestOptions

Configurable options

private static RequestOptions getRequestOptions() { RequestOptions options = new RequestOptions(); //options.format(decodeformat.prefer_argb_8888)// options.centerCrop()// options.placeholder(loadingRes)// load images //options.error(errorRes)// loading the wrong image // Options. error(new ColorDrawable(color.red))// or a Color value / / options. Priority (priority. HIGH) priority set request / / / / options diskCacheStrategy (diskCacheStrategy. ALL); / / options. DiskCacheStrategy (diskCacheStrategy. RESOURCE) / / cache the original picture / / options. The only diskCacheStrategy diskCacheStrategy. (ALL) / / ALL cache / / options. DiskCacheStrategy (diskCacheStrategy. AUTOMATIC) cache thumbnail before / / options. OnlyRetrieveFromCache (true) / / only loaded from the cache / / options. SkipMemoryCache (true) / / disable caching, including memory and disk / / options diskCacheStrategy (diskCacheStrategy. NONE) just skip the disk cache Override (200,200) loads a fixed size image. // options.donttransform () does not do a fade in //options.transition(new) DrawableTransitionOptions (.) dontTransition above ()) / / / / options. CircleCrop () set to round head < this is V4.0 new > / / options. The transform (new RoundedCorners(10)) set to RoundedCorners < this is new in V4.0 > return options; }Copy the code

Use the RequestOptions

Glideapp.with (context).asbitmap ().load(url).apply(getRequestOptions())// Use the custom configurationCopy the code

The same thing can be called in a chain structure

GlideApp.with(context) .asBitmap() .load(url) .placeholder(R.drawable.recommender_avatar_default) .error(R.drawable.recommender_avatar_default) //.skipMemoryCache(false) //.dontTransform() .centerCrop() //.diskCacheStrategy(diskCacheStrategy.all)//.priority(priority.high)// Set the request priority. Transition (new BitmapTransitionOptions().crossFade(200)) .into(imageview);Copy the code

Summary: It feels like these two classes are decoupled, and we usually use this kind of chain structure, so the above is just for reference

4, the use of

/** * @param context is associated with its life cycle if it is an activity Glide, cancel loading the image in onStop(), and pass in the Application instance * @param URL if you want to always load the image  * @param target */ public static void loadRoundImg(Context context, String url, ImageView target) {/ / https://github.com/wasabeef/glide-transformations - glide conversion library GlideApp. With (context). The load (url) .placeholder(R.drawable.recommender_avatar_default) .error(R.drawable.recommender_avatar_default) CircleCrop () / / in the chain directly call will do well. The transition (new DrawableTransitionOptions (). The crossFade (1000)) / / fadein effect. The into (target); }Copy the code

/** * @param context is associated with its life cycle if it is an Activity Glide, unload the image in onStop(), and pass in the Application instance * @param URL if you want to always load the image  * @param target */ public static void loadRoundedCornersImg(Context context, String url, ImageView target) { GlideApp.with(context) .load(url) .placeholder(R.drawable.recommender_avatar_default) .error(R.drawable.recommender_avatar_default) .transform(new RoundedCorners(40)) .transition(new DrawableTransitionOptions (). The crossFade (200)) / / fadein effect. Into (target); }Copy the code

Public static void loadSourceImg(Context c, String url,); /** @param c * @param target */ public static void loadSourceImg(Context c, String url, ImageView target) { GlideApp.with(c) .load(url) .transition(new DrawableTransitionOptions().crossFade(200)) .centercrop () //.sizemultiplier (0.5f)// Use.into(target) if the original image is too big; }Copy the code

** @param c * @param url * @param target */ public static void loadSourseImgWithNoCache(Context c, String url, ImageView target) { GlideApp.with(c) .load(url) .diskCacheStrategy(DiskCacheStrategy.NONE) .skipMemoryCache(true) .centerCrop() .transition(new DrawableTransitionOptions().crossFade(200)) .into(target); } /** * public static void ** @param c * @param resourceId * @param target * @param defaultId */ loadResourseImg(Context c, int resourceId, ImageView target, int defaultId) { GlideApp.with(c) .load(resourceId) .placeholder(defaultId) .transition(new DrawableTransitionOptions().crossFade(200)) .centerCrop() .into(target); } /** * @param c * @param imgFile * @param target * @param defaultId */ public static void loadFileImg(Context c, File imgFile, ImageView target, int defaultId) { GlideApp.with(c) .load(imgFile) .placeholder(defaultId) .transition(new DrawableTransitionOptions().crossFade(200)) .centerCrop() .into(target); } public static void LoadGiftAsBitmap(contextcontext) {public static void LoadGiftAsBitmap(contextcontext); String url, ImageView imageView) { GlideApp.with(context).asBitmap().load(url).into(imageView); } /** * public static void LoadGiftAsGist(context context, context) String url, ImageView imageView, int erroId) { GlideApp.with(context).asGif().load(url).error(erroId).into(imageView); // glideapp.with (context).load(url) //.diskCacheStrategy(diskCacheStrategy.source) //.into(new) GlideDrawableImageViewTarget(imageView,1)); } /** * Loading thumbnails will automatically bind the life cycle to incoming fragments. Loading requests will now automatically be paused in onStop and restarted in onStart. * Make sure ScaleType is set correctly. * * @param fragment * @param url * @param imageView */ public static void LoadThumbNail(Fragment fragment, String url, ImageView ImageView) {GlideApp. With (fragments). The load (url). The thumbnail (0.1 f) into (ImageView); } /** * Upload a picture of the user's avatar with the size of xPx*yPx pixels ** @param context * @param URL * @param xPx* @param yPx */ public static void */ @param context * @param url * @param xPx* @param yPx */ public static void */ decodeResorse(Context context, File url, int xPx, int yPx) { GlideApp .with(context) .load(url) .into(new SimpleTarget<Drawable>(xPx, YPx) {@override public void onResourceReady(Drawable resource, Transition<? Super Drawable> Transition) {  } /** * display local video (network video invalid) ** @param context * @param filePath * @param imageView */ public static void LoadShowLocalVidio(Context context, String filePath, ImageView imageView) { GlideApp.with(context).load(Uri.fromFile(new File(filePath))).into(imageView); } /** * Display images requested from network in the notification bar ** @param context * @param remoteViews * @param viewId * @param notification * @param notificationId * @param url */ public static void ShowImgInNotification(Context context, RemoteViews remoteViews, int viewId, Notification notification, int notificationId, String url) { NotificationTarget target = new NotificationTarget(context, viewId, remoteViews, notification, notificationId); GlideApp.with(context.getApplicationContext()).asBitmap().load(url).into(target); } /** * public static void downLoadImage(context context, @param url) String url) { try { GlideApp.with(context).asBitmap().load(url).centerCrop().listener(new RequestListener<Bitmap>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) { return false; } }).submit().get(); } catch (Exception e) { e.printStackTrace(); Public void clearCache(final context context) {clearMemoryCache(context); new Thread(new Runnable() { @Override public void run() { clearDiskCache(context); } }).start(); Public void clearMemoryCache(context context) {/** * clear the memory cache ** @param */ public void clearMemoryCache(context context) { GlideApp.get(context).clearMemory(); } /** * clearDiskCache ** @param context */ public void clearDiskCache(context context) { GlideApp.get(context).clearDiskCache(); }Copy the code

5. Questions about the use of graphics transformation BitmapTransformation

The previous way of using bitmaptranstion does not work in V4 and the following methods must be implemented

@Override
  public void updateDiskCacheKey(MessageDigest messageDigest) {
   
  }
Copy the code
/** * Created by wangfei on 2016/6/21 18:25. */ Public Class RotateTransformation extends BitmapTransformation { private float rotateRotationAngle = 0f; public RotateTransformation( float rotateRotationAngle) { this.rotateRotationAngle = rotateRotationAngle; } @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { Matrix matrix = new Matrix(); matrix.postRotate(rotateRotationAngle); return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true); } @Override public void updateDiskCacheKey(MessageDigest messageDigest) { } }Copy the code

Okay, so let’s just do an empty implementation and run it

GlideApp.with(context) .load(url) .placeholder(R.drawable.recommender_avatar_default) .error(R.drawable.recommender_avatar_default) .transform(new RotateTransformation(180)) .transition(new DrawableTransitionOptions (). The crossFade (1000)) / / fadein effect. Into (target);Copy the code

But when you reload the data, it looks like you’ve reconverted it

So let’s take a look at the image conversion operation in the library

/** * A Glide {@link BitmapTransformation} to circle crop an image. Behaves similar to a * {@link FitCenter} transform, but the resulting image is masked to a circle. * * <p> Uses a PorterDuff blend mode, see http://ssp.impulsetrain.com/porterduff.html. </p> */ public class CircleCrop extends BitmapTransformation { // The version of this transformation, incremented to correct an error in a previous version. // See #455. private static final int VERSION = 1; private static final String ID = "com.bumptech.glide.load.resource.bitmap.CircleCrop." + VERSION; private static final byte[] ID_BYTES = ID.getBytes(CHARSET); public CircleCrop() { // Intentionally empty. } /** * @deprecated Use {@link #CircleCrop()}. */ @Deprecated public CircleCrop(@SuppressWarnings("unused") Context context) { this(); } /** * @deprecated Use {@link #CircleCrop()} */ @Deprecated public CircleCrop(@SuppressWarnings("unused") BitmapPool bitmapPool) { this(); } // Bitmap doesn't implement equals, so == and .equals are equivalent here. @SuppressWarnings("PMD.CompareObjectsWithEquals") @Override protected Bitmap transform( @NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { return TransformationUtils.circleCrop(pool, toTransform, outWidth, outHeight); } @Override public boolean equals(Object o) { return o instanceof CircleCrop; } @Override public int hashCode() { return ID.hashCode(); } @Override public void updateDiskCacheKey(MessageDigest messageDigest) { messageDigest.update(ID_BYTES); }}Copy the code

Ok, so let’s try it his way

/** * Created by wangfei on 2016/6/21 18:25. */ Public Class RotateTransformation extends BitmapTransformation { private static final String ID = "com.wjf.fastdev.network.glide.RotateTransformation"; private static final byte[] ID_BYTES = ID.getBytes(CHARSET); private float rotateRotationAngle = 0f; public RotateTransformation( float rotateRotationAngle) { this.rotateRotationAngle = rotateRotationAngle; } @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { Matrix matrix = new Matrix(); matrix.postRotate(rotateRotationAngle); return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true); } @Override public boolean equals(Object o) { return o instanceof RotateTransformation; } @Override public int hashCode() { return ID.hashCode(); } @Override public void updateDiskCacheKey(MessageDigest messageDigest) { messageDigest.update(ID_BYTES); }}Copy the code

The results do not show the flashing problem < figure is not uploaded……. >

Resolve the problem that custom BitmapTransformation does not take effect

1, custom class variables private static final String ID = "HTTP: / / com.wjf.fastdev.net work. Glide. RotateTransformation"; private static final byte[] ID_BYTES = ID.getBytes(CHARSET);Copy the code
@override public Boolean equals(Object o) {return instanceof RotateTransformation; } @Override public int hashCode() { return ID.hashCode(); } @Override public void updateDiskCacheKey(MessageDigest messageDigest) { messageDigest.update(ID_BYTES); }Copy the code

All right, here we go. It’s 12 o ‘clock, go to bed, and I have a lot of work to do tomorrow. What problem we discuss together in the comments section, this article is not complete, what shortcomings please everyone to bear, as the title said, is shallow solution……..

# If I find any problems in the future, I will update the article in time. I don't ask how many people will be pleased. It's convenient to use, at least don't mislead peopleCopy the code