如何在片段中实现 GlideApp?
How do I implement GlideApp in a fragment?
我正在尝试使用 kotlin 从片段中的 Firebase 存储中获取图片,但它无法正常工作。这是代码:
val data = FirebaseStorage.getInstance()
val storageRef = data.getReference()
val pathReference = storageRef.child(user.uid.toString() + "/images/coverphoto/")
GlideApp.with(context)
.load(pathReference)
.into(view.profileUserCoverPhoto)
这给了我错误:Required: Context Found: Context?
我也尝试了 GlideApp.with(this@Profile)
和 GlideApp.with(view.context)
(我将我的观点膨胀到 view
这就是我尝试这样做的原因。我无法弄清楚上下文应该是什么,我相信那是问题。图像上传到 Firebase 就好了,所以我知道它在那里。我相信错误出在我的滑动代码上。特别是代码的 context
部分,但我不知道我做错了什么或者我应该使用什么。任何帮助将不胜感激。
*****更新*****
我刚刚使用来自网络的 URL 测试了 Glide,它工作正常。我也刚刚用 firebase URL 对图像“https://firebasestorage.googleapis.com/v0/b/cyber-chatter.appspot.com/o/8YiLlLOxRgO2FjF9OSUKBeL7ckn2%2Fimages%2Fcoverphoto?alt=media&token=7876830c-393f-4a00-be61-80fbd775cf28”进行了测试,效果也很好。我检查了我的 pathReference,它正在正确构建。
这令人困惑和沮丧。我已经尝试找出解决方案 3 天了。我不知道我做错了什么...
你的编译错误:
Required: Context Found: Context?
是由于Fragment.getContext()方法被注解了@Nullable。如果未附加该片段,它将 return 为空。
context?.let { // If context is not null use it in the passed block as `it`
GlideApp.with(it)
.load(pathReference)
.into(view.profileUserCoverPhoto)
}
参见:https://kotlinlang.org/docs/reference/null-safety.html or Kotlin In Action 6.1 https://www.manning.com/books/kotlin-in-action
在 kotlin 中,数据类型可以是 Nullable 或 Non-Nullable。为了标记为可空,我们使用问号。
这是不可空的
var c: Context // Equivalent to @NonNullable Context c;
这是可空的
var c: Context? // Equivalent to @Nullable Context c;
现在,您的 GlideApp 需要一个不可为空的上下文。但是,您的片段 getContext 方法可以 return null。所以。让我们来看看那个方法。
/**
* Return the {@link Context} this fragment is currently associated with.
*
* @see #requireContext()
*/
@Nullable
public Context getContext() {
return mHost == null ? null : mHost.getContext();
}
@Nullable
final public FragmentActivity getActivity() {
return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
因此,当片段未附加到 activity 时,您可以获得 null。基本上,您可以确定 Fragment 的 onAttach 和 onDetach 方法之间的上下文不为空。
所以在 onCreate 之间你可以使用 Non null assertion
GlideApp.with(getContext()!!)
否则,您可以随时检查上述答案中提到的空值。
getContext()?.let{ GlideApp.with(it) ... }
终于!!我发现了问题:
我的requiredAppGlideModule.kt不正确。对于 kotlin,它应该看起来像这样:
import android.content.Context
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.module.AppGlideModule
import com.google.firebase.storage.StorageReference
import com.bumptech.glide.Glide
import com.bumptech.glide.Registry
import com.firebase.ui.storage.images.FirebaseImageLoader
import java.io.InputStream
import com.google.firebase.FirebaseOptions.Builder
@GlideModule
class RequiredAppGlideModule : AppGlideModule() {
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
// Register FirebaseImageLoader to handle StorageReference
registry.append(StorageReference::class.java, InputStream::class.java,
FirebaseImageLoader.Factory())
}
}
一旦我这样做并添加了上面显示的所有正确导入引用,我就收到了 FirebaseImageLoader
的未知引用错误,所以我还使用以下代码创建了 FirebaseImageLoader.kt class:
package com.firebase.ui.storage.images
import android.util.Log
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.Key
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.ModelLoaderFactory
import com.bumptech.glide.load.model.MultiModelLoaderFactory
import com.google.android.gms.tasks.OnFailureListener
import com.google.android.gms.tasks.OnSuccessListener
import com.google.firebase.storage.StorageReference
import com.google.firebase.storage.StreamDownloadTask
import java.io.IOException
import java.io.InputStream
import java.nio.charset.Charset
import java.security.MessageDigest
/**
* ModelLoader implementation to download images from FirebaseStorage with Glide.
*
*
*
* First, register this class in your AppGlideModule:
* <pre>
* @Override
* public void registerComponents(Context context, Registry registry) {
* // Register FirebaseImageLoader to handle StorageReference
* registry.append(StorageReference.class, InputStream.class,
* new FirebaseImageLoader.Factory());
* }
</pre> *
*
*
*
* Then load a StorageReference into an ImageView.
* <pre>
* StorageReference ref = FirebaseStorage.getInstance().getReference().child("myimage");
* ImageView iv = (ImageView) findViewById(R.id.my_image_view);
*
* GlideApp.with(this)
* .load(ref)
* .into(iv);
</pre> *
*/
class FirebaseImageLoader : ModelLoader<StorageReference, InputStream> {
/**
* Factory to create [FirebaseImageLoader].
*/
class Factory : ModelLoaderFactory<StorageReference, InputStream> {
override fun build(factory: MultiModelLoaderFactory): ModelLoader<StorageReference, InputStream> {
return FirebaseImageLoader()
}
override fun teardown() {
// No-op
}
}
override fun buildLoadData(reference: StorageReference,
height: Int,
width: Int,
options: Options): ModelLoader.LoadData<InputStream>? {
return ModelLoader.LoadData(
FirebaseStorageKey(reference),
FirebaseStorageFetcher(reference))
}
override fun handles(reference: StorageReference): Boolean {
return true
}
private class FirebaseStorageKey(private val mRef: StorageReference) : Key {
override fun updateDiskCacheKey(digest: MessageDigest) {
digest.update(mRef.path.toByteArray(Charset.defaultCharset()))
}
}
private class FirebaseStorageFetcher(private val mRef: StorageReference) : DataFetcher<InputStream> {
private var mStreamTask: StreamDownloadTask? = null
private var mInputStream: InputStream? = null
override fun loadData(priority: Priority,
callback: DataFetcher.DataCallback<in InputStream>) {
mStreamTask = mRef.stream
mStreamTask!!
.addOnSuccessListener { snapshot ->
mInputStream = snapshot.stream
callback.onDataReady(mInputStream)
}
.addOnFailureListener { e -> callback.onLoadFailed(e) }
}
override fun cleanup() {
// Close stream if possible
if (mInputStream != null) {
try {
mInputStream!!.close()
mInputStream = null
} catch (e: IOException) {
Log.w(TAG, "Could not close stream", e)
}
}
}
override fun cancel() {
// Cancel task if possible
if (mStreamTask != null && mStreamTask!!.isInProgress) {
mStreamTask!!.cancel()
}
}
override fun getDataClass(): Class<InputStream> {
return InputStream::class.java
}
override fun getDataSource(): DataSource {
return DataSource.REMOTE
}
}
companion object {
private val TAG = "FirebaseImageLoader"
}
}
然后我将它导入到我的 requiredAppGlideModule.kt
中,当我完成这两件事后,图像加载就完全没有问题了!干杯!
我正在尝试使用 kotlin 从片段中的 Firebase 存储中获取图片,但它无法正常工作。这是代码:
val data = FirebaseStorage.getInstance()
val storageRef = data.getReference()
val pathReference = storageRef.child(user.uid.toString() + "/images/coverphoto/")
GlideApp.with(context)
.load(pathReference)
.into(view.profileUserCoverPhoto)
这给了我错误:Required: Context Found: Context?
我也尝试了 GlideApp.with(this@Profile)
和 GlideApp.with(view.context)
(我将我的观点膨胀到 view
这就是我尝试这样做的原因。我无法弄清楚上下文应该是什么,我相信那是问题。图像上传到 Firebase 就好了,所以我知道它在那里。我相信错误出在我的滑动代码上。特别是代码的 context
部分,但我不知道我做错了什么或者我应该使用什么。任何帮助将不胜感激。
*****更新*****
我刚刚使用来自网络的 URL 测试了 Glide,它工作正常。我也刚刚用 firebase URL 对图像“https://firebasestorage.googleapis.com/v0/b/cyber-chatter.appspot.com/o/8YiLlLOxRgO2FjF9OSUKBeL7ckn2%2Fimages%2Fcoverphoto?alt=media&token=7876830c-393f-4a00-be61-80fbd775cf28”进行了测试,效果也很好。我检查了我的 pathReference,它正在正确构建。
这令人困惑和沮丧。我已经尝试找出解决方案 3 天了。我不知道我做错了什么...
你的编译错误:
Required: Context Found: Context?
是由于Fragment.getContext()方法被注解了@Nullable。如果未附加该片段,它将 return 为空。
context?.let { // If context is not null use it in the passed block as `it`
GlideApp.with(it)
.load(pathReference)
.into(view.profileUserCoverPhoto)
}
参见:https://kotlinlang.org/docs/reference/null-safety.html or Kotlin In Action 6.1 https://www.manning.com/books/kotlin-in-action
在 kotlin 中,数据类型可以是 Nullable 或 Non-Nullable。为了标记为可空,我们使用问号。 这是不可空的
var c: Context // Equivalent to @NonNullable Context c;
这是可空的
var c: Context? // Equivalent to @Nullable Context c;
现在,您的 GlideApp 需要一个不可为空的上下文。但是,您的片段 getContext 方法可以 return null。所以。让我们来看看那个方法。
/**
* Return the {@link Context} this fragment is currently associated with.
*
* @see #requireContext()
*/
@Nullable
public Context getContext() {
return mHost == null ? null : mHost.getContext();
}
@Nullable
final public FragmentActivity getActivity() {
return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
因此,当片段未附加到 activity 时,您可以获得 null。基本上,您可以确定 Fragment 的 onAttach 和 onDetach 方法之间的上下文不为空。
所以在 onCreate 之间你可以使用 Non null assertion
GlideApp.with(getContext()!!)
否则,您可以随时检查上述答案中提到的空值。
getContext()?.let{ GlideApp.with(it) ... }
终于!!我发现了问题:
我的requiredAppGlideModule.kt不正确。对于 kotlin,它应该看起来像这样:
import android.content.Context
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.module.AppGlideModule
import com.google.firebase.storage.StorageReference
import com.bumptech.glide.Glide
import com.bumptech.glide.Registry
import com.firebase.ui.storage.images.FirebaseImageLoader
import java.io.InputStream
import com.google.firebase.FirebaseOptions.Builder
@GlideModule
class RequiredAppGlideModule : AppGlideModule() {
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
// Register FirebaseImageLoader to handle StorageReference
registry.append(StorageReference::class.java, InputStream::class.java,
FirebaseImageLoader.Factory())
}
}
一旦我这样做并添加了上面显示的所有正确导入引用,我就收到了 FirebaseImageLoader
的未知引用错误,所以我还使用以下代码创建了 FirebaseImageLoader.kt class:
package com.firebase.ui.storage.images
import android.util.Log
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.Key
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.model.ModelLoaderFactory
import com.bumptech.glide.load.model.MultiModelLoaderFactory
import com.google.android.gms.tasks.OnFailureListener
import com.google.android.gms.tasks.OnSuccessListener
import com.google.firebase.storage.StorageReference
import com.google.firebase.storage.StreamDownloadTask
import java.io.IOException
import java.io.InputStream
import java.nio.charset.Charset
import java.security.MessageDigest
/**
* ModelLoader implementation to download images from FirebaseStorage with Glide.
*
*
*
* First, register this class in your AppGlideModule:
* <pre>
* @Override
* public void registerComponents(Context context, Registry registry) {
* // Register FirebaseImageLoader to handle StorageReference
* registry.append(StorageReference.class, InputStream.class,
* new FirebaseImageLoader.Factory());
* }
</pre> *
*
*
*
* Then load a StorageReference into an ImageView.
* <pre>
* StorageReference ref = FirebaseStorage.getInstance().getReference().child("myimage");
* ImageView iv = (ImageView) findViewById(R.id.my_image_view);
*
* GlideApp.with(this)
* .load(ref)
* .into(iv);
</pre> *
*/
class FirebaseImageLoader : ModelLoader<StorageReference, InputStream> {
/**
* Factory to create [FirebaseImageLoader].
*/
class Factory : ModelLoaderFactory<StorageReference, InputStream> {
override fun build(factory: MultiModelLoaderFactory): ModelLoader<StorageReference, InputStream> {
return FirebaseImageLoader()
}
override fun teardown() {
// No-op
}
}
override fun buildLoadData(reference: StorageReference,
height: Int,
width: Int,
options: Options): ModelLoader.LoadData<InputStream>? {
return ModelLoader.LoadData(
FirebaseStorageKey(reference),
FirebaseStorageFetcher(reference))
}
override fun handles(reference: StorageReference): Boolean {
return true
}
private class FirebaseStorageKey(private val mRef: StorageReference) : Key {
override fun updateDiskCacheKey(digest: MessageDigest) {
digest.update(mRef.path.toByteArray(Charset.defaultCharset()))
}
}
private class FirebaseStorageFetcher(private val mRef: StorageReference) : DataFetcher<InputStream> {
private var mStreamTask: StreamDownloadTask? = null
private var mInputStream: InputStream? = null
override fun loadData(priority: Priority,
callback: DataFetcher.DataCallback<in InputStream>) {
mStreamTask = mRef.stream
mStreamTask!!
.addOnSuccessListener { snapshot ->
mInputStream = snapshot.stream
callback.onDataReady(mInputStream)
}
.addOnFailureListener { e -> callback.onLoadFailed(e) }
}
override fun cleanup() {
// Close stream if possible
if (mInputStream != null) {
try {
mInputStream!!.close()
mInputStream = null
} catch (e: IOException) {
Log.w(TAG, "Could not close stream", e)
}
}
}
override fun cancel() {
// Cancel task if possible
if (mStreamTask != null && mStreamTask!!.isInProgress) {
mStreamTask!!.cancel()
}
}
override fun getDataClass(): Class<InputStream> {
return InputStream::class.java
}
override fun getDataSource(): DataSource {
return DataSource.REMOTE
}
}
companion object {
private val TAG = "FirebaseImageLoader"
}
}
然后我将它导入到我的 requiredAppGlideModule.kt
中,当我完成这两件事后,图像加载就完全没有问题了!干杯!