This is how Glide Kotlin should wrap the summary

Glide is an image loading library officially recommended by Google, Coil is the Kotlin-first Android image loading library, integrating Kotlin features, the most mainstream Android technology and trends. In this post, we are going to share how to use The Coil package with Kotlin.

Integration and API preview

  1. allprojects {
    	repositories {
    		maven { url 'https://www.jitpack.io'}}}Copy the code
  2. dependencies {
        implementation 'com. Making. ForJrking: ImageExt: hundreds'
    }
    Copy the code
  3. // URL
    imageView.load("https://www.example.com/image.jpg")
    // Resource
    imageView.load(R.drawable.image)
    // callback and progress monitoring
    imageView.load("https://www.example.com/image.jpg") {
        placeHolderResId = R.drawable.placeholder
        transformation = arrayOf(GrayscaleTransformation())
        progressListener { isComplete, percentage, bytesRead, totalBytes ->
            // Load progress
        }
        requestListener {
            onSuccess {
            }
            onFail {
            }
        }
    }
    Copy the code
  4. Other extension functions and effects

    iv_4.loadCircleImage(url1)
    iv_5.loadBorderImage(url1, borderWidth = 10, borderColor = Color.RED)
    iv_6.loadGrayImage(url1)
    iv_7.loadRoundCornerImage(url1, radius = 40, type = ImageOptions.CornerType.ALL)
    iv_8.loadBlurImage(url4)
    iv_9.loadResizeImage(url3, width = 400, height = 800)
    Copy the code

Encapsulate implementation

Firstly, the call method of the coil is in the form of the Kotlin extension function, adding a load(URL) function to the ImageView. Then, other placeholder configurations are set in DSL mode. How to learn and use DSL is discussed separately below.

The first step is to encapsulate the following function:

/** coil / /
fun ImageView.load(load: Any? , options: (ImageOptions. () - >Unit)? = null) {
    ImageLoader.loadImage(ImageOptions(load).also(options))
}
Copy the code

Step 2 Encapsulates the configuration class:

/** * image load library configuration, encapsulate the original load configuration properties, conversion */
class ImageOptions {
    /*** Load the original resource */
    var res: Any? = null
    /*** displays the container */
    var imageView: ImageView? = null
    /*** imageView exists context or fragment activity*/
    var context: Any? = null
        get() {
            returnfield ? : imageView }/*** load placeholder resource ID. Placeholder 0 means no placeholder */
    @DrawableRes
    var placeHolderResId = 0. Omit animations, error diagrams, and other attributesvar centerCrop: Boolean = false
    /*** Network progress listener */
    var onProgressListener: OnProgressListener? = null
    /*** load listener */
    var requestListener: OnImageListener? = null. Omit enumerations like cache policy and priority}Copy the code

The third step strategy implementation, because to use OKHTTP interceptor to do progress monitoring, through annotations configuration glide’s network download.

/**Glide package */
object ImageLoader {
    fun loadImage(options: ImageOptions) {
        Preconditions.checkNotNull(options, "ImageConfigImpl is required")
        val context = options.context
        Preconditions.checkNotNull(context, "Context is required")
        Preconditions.checkNotNull(options.imageView, "ImageView is required")
        val requestsWith = glideRequests(context)
        // By type
        val glideRequest = when (options.res) {
            is String -> requestsWith.load(options.res as String)
            is Bitmap -> requestsWith.load(options.res as Bitmap)
            is Drawable -> requestsWith.load(options.res as Drawable)
            is Uri -> requestsWith.load(options.res as Uri)
            is URL -> requestsWith.load(options.res as URL)
            is File -> requestsWith.load(options.res as File)
            is Int -> requestsWith.load(options.res as Int)
            is ByteArray -> requestsWith.load(options.res as ByteArray)
            else -> requestsWith.load(options.res)
        }

        glideRequest.apply {
            // Error map.// Cache configuration, priority, thumbnail request.// Animation, Transformationinto(GlideImageViewTarget(options.imageView, options.res)) } options.onProgressListener? .let { ProgressManager.addListener(options.res.toString(), options.onProgressListener) } }private fun glideRequests(context: Any?).: GlideRequests {
        return when (context) {
            is Context -> IGlideModule.with(context)
            is Activity -> IGlideModule.with(context)
            is FragmentActivity -> IGlideModule.with(context)
            is Fragment -> IGlideModule.with(context)
            is android.app.Fragment -> IGlideModule.with(context)
            is View -> IGlideModule.with(context)
            else -> throw NullPointerException("not support")}}}Copy the code

Kotlin DSL

Writing a DSL can be easily understood and memorized with the following code (main reference: How to make your callbacks Kotlin)

class DSLTest{
  // Common variables
  var str:String? =null
  // Function variable
  var onSuccess: ((String?) -> Unit)? = null
	// Call a function variable
  fun onSuccessDo(a){... onSuccess.invoke("success $str")}}// Define the function to call
load(dslPar:(DSLTest.() -> Unit)? = null){
   DSLTest().also(dslPar)
}
/ / use
load{
  str = "ACC"
  onSuccess{
    //TODO}}Copy the code

Compared with traditional policy mode encapsulation

  • Define the policy pattern base interface
/** image loading policy interface */
public interface BaseImageLoaderStrategy {
    void loadImage(load Any,ImageOptions options);
}
Copy the code
  • Implementation policy Interface
/*** Specific load strategy, Glide load framework */
public class GlideImageLoader implements BaseImageLoaderStrategy {
    @Override
    public void loadImage(Context context, ImageOptions options) {
        Glide.with(context).apply(...).into(options.getImgView());
    }
}
Copy the code
  • Policy scheduler call
ImageLoader.loadImage(ImageOptions(imageView).apply{
	.....
})
Copy the code

Policy mode usually encapsulates many interfaces to meet everyday needs. Due to Kotlin, we can encapsulate a method with very long arguments and call it with optional arguments, but Java can’t do anything except assign null to the optional arguments.

// Optional parameter Example
load(url:String,isCirle:Boolean = false, width:Int=0, height:Int = 0) {... }// Use the parameter name = value to use optional arguments
iv_8.load(url2, height = 800)
Copy the code

Comparison between policy encapsulation and extension function +DSL:

  • Unified interface encapsulation, all with extensibility
  • You can use the Kotlin feature without having to define a lot of interfaces
  • Extension functions are more convenient and concise
  • The way the DSL is written makes the code more understandable and kotlin-style
  • A multimethod interface callback that allows you to select only individual methods

conclusion

  • Finally, package and distribute the JitPack repository, project open source addresses and documentation for easy use in your project

ForJrking /ImageExt: Extension function set for loading image resources based on Glide packaging ImageView (github.com)

  • Because of the okHTTP-based download schedule management, glide @glidemodule configuration method is used. This may conflict with your project custom configuration, so we can only pull the code to modify, and rely on Module mode. Contact me if there is a better way to improve.

  • There are only a few common Android image loading libraries, and other libraries can be implemented by reference. Kotlin smells good!!