如何在片段中实现GlideApp?

时间:2018-09-04 22:16:05

标签: android-fragments kotlin android-glide

我正在尝试从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部分,但是我不知道自己在做什么错或做什么。我应该使用,任何帮助将不胜感激。

*****更新*****

我刚刚使用Web上的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天了。我不知道我在做什么错...

3 个答案:

答案 0 :(得分:0)

您的编译错误:

  

必填:找到上下文:上下文?

是由于Fragment.getContext()方法被@Nullable注解。如果未附加该片段,它将返回null。

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或Kotlin In Action 6.1 https://www.manning.com/books/kotlin-in-action

答案 1 :(得分:0)

在kotlin中,数据类型可以为Nullable或Non-Nullable。为了标记为可空,我们使用问号。 这是不可空的

var c: Context // Equivalent to @NonNullable Context c;

这是空的

var c: Context? // Equivalent to @Nullable Context c;

现在,您的GlideApp需要一个不可为空的上下文。但是,您的片段getContext方法可以返回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();
    }

因此,当片段未附加到活动时,您将获得null。基本上,可以确保Fragment的onAttach和onDetach方法之间的上下文不为空。

因此,在两次创建之间,您可以使用Non null断言

GlideApp.with(getContext()!!)

否则,您始终可以如上述答案中所述检查空值。

getContext()?.let{ GlideApp.with(it) ... }  

https://developer.android.com/images/fragment_lifecycle.png

答案 2 :(得分:0)

最后!我发现了问题:

我所需的AppGlideModule.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类:

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中,并且当我完成这两件事后,图像加载就没有问题了!干杯!