滑行版本:4.9.0

我试图自定义RequestBuilder类,以具有自定义的生成器,在这种情况下,我想自定义RequestBuilder#addListener函数以具有@FunctionalInterfaceFunction0<R>作为参数,并且要对Java 8起作用。

我试图阅读有关@GlideExtensions here的文档以及以下内容之间的区别:


@GlideOption:用于添加自定义的RequestOptions,只要在这种情况下BaseRequestOptions<*>的第一个参数是从RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>扩展而来的
@GlideType:绝对创建其他类型的drawable,没有做太多配置,因此我没有尝试。


由于RequestListener没有@FunctionalInterface批注,我最终使用Kotlin和Java 8来实现类似lambda的参数功能。

我创建了一个SafeGlideApp类来处理与上下文相关的问题using RequestManager inside onCreatechecking if the activity isFinishing

class SafeGlideApp {

    companion object {

        private lateinit var rm: RequestManager
        private lateinit var target: ViewTarget<ImageView, Drawable>

        /**
         * This is mandatory to setup inside onCreate() on any Activity/Fragment
         * @param Activity receive the current activity if not finishing
         */
        @JvmStatic
        fun init(activity: Activity) {
            rm = Glide.with(activity)
        }

        @JvmStatic
        fun destroy() {
            target.clearOnDetach()
            rm.pauseAllRequests()
            rm.clear(target)
        }

        @JvmStatic
        fun with(activity: Activity, safeAction: (RequestManager) -> ViewTarget<ImageView, Drawable>) {
            init(activity)
            activity.safeRunnable {
                check(::rm.isInitialized)
                target = safeAction(rm)
            }
        }
    }
}


这是在SafeGlideApp上调用自定义侦听器所需的功能。

Activity.java

SafeGlideApp.with(this, requestManager -> requestManager
                        .load(url)
                        .listener(
                                Helpers.wrapper(() -> doSomething()),
                                Helpers.wrapper(() -> doSomething())
                        )
                        .into(imageView)
);


为了在kotlin-java之间实现互操作,我创建了这个受stackoverflow中每个人启发的包装器。因此,在调用调用中,更加简洁。

Helpers.java

    /**
     * This lambda wrapper function takes nothing as argument and return Unit
     * E.g: f(wrapper(() -> doSomethingVoid()))
     *
     * @param callable
     * @return Unit
     */
    public static Function0<Unit> wrapper(Runnable callable) {
        return () -> {
            callable.run();
            return Unit.INSTANCE;
        };
    }


到目前为止,这是我自定义RequestBuilder的方法。

我的通用侦听器类

CustomListener.kt

fun <T : Any> makeLoadingRequestListener(
        failedAction: (() -> Unit)?,
        readyAction: (() -> Unit)?
): RequestListener<T> = object : RequestListener<T> {
    override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<T>?, isFirstResource: Boolean): Boolean {
        failedAction?.invoke()
        return false
    }

    override fun onResourceReady(resource: T, model: Any?, target: Target<T>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
        readyAction?.invoke()
        return false
    }
}


故障排除


使用显式类型Drawable将产生编译错误:


e: [kapt] An exception occurred: java.lang.IllegalArgumentException:
   @GlideOption methods must take a BaseRequestOptions<?> object as
   their first parameter, but the first parameter in
   MyAppGlideExtension#listener(RequestBuilder, Unit, Unit) is
   RequestBuilder<Drawable>


这是我的扩展类MyGlideExtension.kt

@GlideExtension
open class MyAppGlideExtension private constructor() {

    companion object {

        @JvmStatic
        @GlideOption
        fun listener(
                options: RequestBuilder<Drawable>,
                failedAction: () -> Unit,
                readyAction: () -> Unit
        ): BaseRequestOptions<Drawable> {
            return options.addListener(makeLoadingRequestListener<Drawable>(
                    failedAction = failedAction,
                    readyAction = readyAction
            ))
        }
    }
}


如本期#3552#4030所述。 FlickrGlideExtension示例正在使用Java。另外,作者声明在Kotlin中使用?通配符,实际上Kotlin不支持。


我也尝试过这样的java方法,并且也有编译错误


@GlideExtension
public final class MyGlideExtension {

    private MyGlideExtension GlideExtension() {
        return this;
    }

    @GlideOption
    public static BaseRequestOptions<?> test(RequestBuilder<?> requestBuilder,
                                             Function0<Unit> failed,
                                             Function0<Unit> ready) {
        return requestBuilder.listener(new RequestListener<Object>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Object> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(Object resource, Object model, Target<Object> target, DataSource dataSource, boolean isFirstResource) {
                return false;
            }
        });
    }
}



不幸的是,我不知道如何使用投影来解决此问题。投影类型禁止使用RequestBuilder#addListener功能


@GlideExtension
open class MyAppGlideExtension private constructor() {

    companion object {

        @JvmStatic
        @GlideOption
        fun listener(
                options: RequestBuilder<*>,
                failedAction: () -> Unit,
                readyAction: () -> Unit
        ): BaseRequestOptions<*> {
            return options.addListener(makeLoadingRequestListener<Object>(
                    failedAction = failedAction,
                    readyAction = readyAction
            ))
        }
    }
}



手动扩展RequestManagerRequestBuilder


class CustomRequestManager(
        glide: Glide, lifecycle: Lifecycle,
        treeNode: RequestManagerTreeNode, context: Context
) : RequestManager(glide, lifecycle, treeNode, context) {

    override fun load(string: String?): CustomRequestBuilder<Drawable> {
        return super.load(string) as CustomRequestBuilder<Drawable>
    }
}

class CustomRequestBuilder<TranscodeType : Any>(
        glide: Glide,
        requestManager: RequestManager,
        transcodeClass: Class<TranscodeType>,
        context: Context
) : RequestBuilder<TranscodeType>(glide, requestManager, transcodeClass, context) {

    fun listener(failedAction: () -> Unit, readyAction: () -> Unit): RequestBuilder<TranscodeType> {
        return addListener(makeLoadingRequestListener<TranscodeType>(
                failedAction = failedAction,
                readyAction = readyAction
        ))
    }
}


但是在投射GlideApp.with(this) as CustomRequestManager时失败,并抛出编译错误:GlideRequest cannot be casted to CustomRequestManager

最后但并非最不重要的。


有没有可能扩展/自定义RequestBuilder类的方法?
还是可以在不扩展RequestBuilder的情况下创建帮助器类?
&包装RequestListener<R>接口是否起作用?

最佳答案

我认为您需要从字面上接受错误消息:

    @JvmStatic
    @GlideOption
    fun listener(
            options: RequestBuilder<Drawable>,
            failedAction: () -> Unit,
            readyAction: () -> Unit
    ): BaseRequestOptions<Drawable> {




    @JvmStatic
    @GlideOption
    fun listener(
            options: RequestBuilder<*>, // no explicit type, wildcard only (=== Java's <?>)
            failedAction: () -> Unit,
            readyAction: () -> Unit
    ): BaseRequestOptions<*> {




    @JvmStatic
    @GlideOption
    fun listener(
            options: BaseRequestOptions<*>, // not a subtype, exactly that type
            failedAction: () -> Unit,
            readyAction: () -> Unit
    ): BaseRequestOptions<*> {


然后可以根据需要将options参数强制转换为RequestOptions或生成的类的类型。

08-03 21:13