【发布时间】:2019-12-31 05:03:04
【问题描述】:
Glide 版本:4.9.0
我尝试自定义 RequestBuilder 类,以获得自定义构建器,在这种情况下,我想自定义 RequestBuilder#addListener 函数以将 @FunctionalInterface 或 Function0<R> 作为参数并适用于 Java 8。
我尝试阅读有关 @GlideExtensions here 的文档以及两者之间的区别:
-
@GlideOption:用于添加自定义RequestOptions,只要第一个参数是从BaseRequestOptions<*>扩展而来的,在这种情况下RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>> -
@GlideType:肯定是创建不同类型的drawable,没有做太多配置,所以我没有尝试。
由于 RequestListener 没有 @FunctionalInterface 注释,我最终使用 Kotlin 和 Java 8 来实现 lambda-like 参数函数。
我创建了一个SafeGlideApp 类来处理与上下文相关的问题using RequestManager inside onCreate 和checking 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
))
}
}
}
- 手动扩展
RequestManager&RequestBuilder
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>接口以使其正常工作?
【问题讨论】:
-
已编辑:我认为,我不必经历所有这些并想到一个替代选项:1. fork the glide,并创建不同的 GlideExtensions 功能 2. 只需迁移到 kotlin(这将绝对符合我想要的功能方法)3.创建一个包装器方法(静态)来接收一个返回
RequestListener<Drawable>的lambda -
错误是什么? “我也试过这样的java方法,也有编译错误”
-
@TWiStErRob
addListener(RequestListener<capture<?>>) cannot be applied to (RequestListener<Object>) -
这很好,我想。听起来注释处理器通过了,但是由于类型错误,您的代码中有错误。
标签: java android kotlin android-glide appglidemodule