【问题标题】:Despite initialization, lateinit property has not been initialized in Fragment尽管进行了初始化,但在 Fragment 中还没有初始化 lateinit 属性
【发布时间】:2020-07-30 20:23:26
【问题描述】:

问候, 我有一个从 Firestore 中提取数据的 FirestoreRecyclerAdapter。在提取数据之前,我想展示一个方便工作的骨架视图。为了在拉取数据时通知 Fragment,我使用了一个侦听器。但是,当我在 Fragment 中覆盖此侦听器接口的方法时,由于某种原因,我的 recyclerView 得到“kotlin.UninitializedPropertyAccessException:lateinit 属性 rvShops 尚未初始化”,即使它们在触发接口方法时已初始化.我的代码sn-ps如下:

class ShopsFragment : Fragment(), ShopsLoadedListener {
companion object {
    fun newInstance(): ShopsFragment {
        return ShopsFragment()
    }
}

private lateinit var colRefShops: CollectionReference
private lateinit var shopAdapter: ShopAdapter
private lateinit var v: View
private lateinit var b: FragmentShopsBinding
private lateinit var skeleton: Skeleton

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    arguments?.let {
    }
    (activity as MainActivity).tabLayoutShops.visibility = View.GONE
    colRefShops = FirebaseFirestore.getInstance().collection(DB_SHOPS)

}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    v = inflater.inflate(R.layout.fragment_shops, container, false)
    return v
}


override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    initRecyclerView()
}

  override fun onStart() {
    super.onStart()
    shopAdapter.startListening()
}

private fun initRecyclerView() {
    rvShops?.layoutManager = GridLayoutManager(v.context, 2)
    skeleton = skelOutShops
    skeleton = rvShops.applySkeleton(R.layout.item_shop, 10)
    skeleton.showSkeleton()

    val q: Query = colRefShops.orderBy(WEIGHT)
    val options: FirestoreRecyclerOptions<ModelShop> =
        FirestoreRecyclerOptions.Builder<ModelShop>()
            .setQuery(q, ModelShop::class.java)
            .build()
    shopAdapter = ShopAdapter(options, shopsLoadedListener = newInstance())

}

override fun onStop() {
    super.onStop()
    shopAdapter.stopListening()
}

override fun onShopsLoaded(i: Int) {

    Log.d("dataComes", "Data = $i")
    rvShops.adapter = shopAdapter //here i get kotlin.UninitializedPropertyAccessException: lateinit property rvShops has not been initialized when this method is fired up
    skeleton.showOriginal()
}
}

我的适配器:

class ShopAdapter(options: FirestoreRecyclerOptions<ModelShop>, private var shopsLoadedListener: ShopsLoadedListener)
: FirestoreRecyclerAdapter<ModelShop, ShopAdapter.ShopViewHolder>(options) {

override fun onDataChanged() {
    super.onDataChanged()
    shopsLoadedListener.onShopsLoaded(5)
}

private var v: View? = null
public interface ShopsLoadedListener{
    fun onShopsLoaded(i: Int)
}


class ShopViewHolder(private val b: ItemShopBinding) : RecyclerView.ViewHolder(b.root)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ShopViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    val v = layoutInflater.inflate(R.layout.item_shop, parent, false)
    val b = ItemShopBinding.inflate(layoutInflater)
    Log.d("fire", "ifireincreateviewholder")

    return ShopViewHolder(b)
}

 override fun onBindViewHolder(vHolder: ShopViewHolder, i: Int, modelShop: ModelShop) {
    vHolder.itemView.tvShopName.text = modelShop.displayName
     Glide.with(vHolder.itemView.context)
         .load(modelShop.logoURL)
         .centerCrop()
         .into(vHolder.itemView.ivShopLogo)
}
}

【问题讨论】:

    标签: android kotlin google-cloud-firestore


    【解决方案1】:

    错误消息告诉您在分配值之前尝试使用skeleton。几乎可以肯定,onShopsLoadedinitRecyclerView 可以初始化之前被调用。您将不得不编写代码来检测这种情况并正确处理它。

    【讨论】:

    • 这很奇怪。 initRecyclerView() 在 onShopsLoaded() 之前被调用,我在 initRecyclerView() 和 onShopsLoaded() 中的日志证明了这一点。 i.imgur.com/K5E1SGm.png 正如你在这里看到的,我在崩溃前得到了一个骨架网格布局,网格中每行有两个项目,这意味着 rvShops?.layoutManager = GridLayoutManager(v.context, 2) 执行得很好。但是当 onShopsLoaded() 里面的代码被触发时,突然 rvShops 为空。另外,如果您说骨架未正确初始化,那么为什么skeleton.showSkeleton() 也可以正常执行?
    • 顺便说一句,我现在明白你的意思了,我发布了错误消息说骨架不是初始化,但即使我删除了关于骨架的所有内容,rvShops 在重写的接口方法,这就是我想要说明的重点。
    • 不过,这将是基本相同的问题。您在分配之前使用了 rvShops。
    • i.imgur.com/t1MgBrC.png - 这是我的 onViewCreated() 现在,问题仍然存在。我确信在这种情况下完成了初始化。当我执行“rvShops?.layoutManager = GridLayoutManager(v.context, 2)”时,按照相同的逻辑,我在分配 rvShops 之前使用它,但没有引发错误并且代码按预期执行。我觉得问题出在其他地方,它特定于被覆盖的 onShopsLoaded() 的范围
    • 您的代码根本没有真正分配 rvShops,至少不是您在此处显示的内容。
    【解决方案2】:

    据我所知,您永远不会将 rvShops 分配给任何东西,这会导致它未初始化。鉴于它设置为lateinit,因此您获得UninitializedPropertyAccessException 是有道理的。

    解决方案:

    在您的片段中分配onViewCreated(...) 中的rvShops,这不应该再像那样崩溃了。

    【讨论】:

    • 分配是什么意思?如果您像 Java 方式一样谈论“rvShops = v.findViewById(R.id.rvShops)”,我仍然会得到“lateinit 属性 rvShops 尚未初始化”。我的 onCreateView() 如下:i.imgur.com/t1MgBrC.png
    【解决方案3】:
    private fun initRecyclerView() {
    rvShops?.layoutManager = GridLayoutManager(v.context, 2)
    skeleton = skelOutShops
    skeleton = rvShops.applySkeleton(R.layout.item_shop, 10)
    skeleton.showSkeleton()
    
    val q: Query = colRefShops.orderBy(WEIGHT)
    val options: FirestoreRecyclerOptions<ModelShop> =
        FirestoreRecyclerOptions.Builder<ModelShop>()
            .setQuery(q, ModelShop::class.java)
            .build()
    shopAdapter = ShopAdapter(options, shopsLoadedListener = newInstance())
    }
    

    原来问题出在这个函数上,尤其是这一行:

    shopAdapter = ShopAdapter(options, shopsLoadedListener = newInstance())
    

    创建这个监听器实例的正确方法应该是:

    shopAdapter = ShopAdapter(options, this)
    

    在这种情况下,我实现的方法也可以正常工作。

    【讨论】:

      猜你喜欢
      • 2020-01-18
      • 2018-10-12
      • 1970-01-01
      • 1970-01-01
      • 2017-03-03
      • 1970-01-01
      • 1970-01-01
      • 2020-12-31
      • 2021-06-11
      相关资源
      最近更新 更多