滑行版本: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的参数功能。
我创建了一个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>
接口是否起作用? 最佳答案
我认为您需要从字面上接受错误消息:
@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
或生成的类的类型。