[将Firestore与Fragment和ViewModel一起使用时Android应用程序崩溃

问题描述 投票:0回答:1

我有一个应用,可显示MainActivity中片段的产品列表。使用ViewModel通过Repository从Firestore数据库中读取项目列表。

MainActivtiy:

class MainActivity : AppCompatActivity() {

    private val model: ProductViewModel by lazy {
        ViewModelProvider(this).get(ProductViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        supportFragmentManager.beginTransaction().replace(R.id.fragment, ProductListFragment())
            .commit()
...

ProductListFragment:

class ProductListFragment : Fragment() {
    private val model: ProductViewModel by lazy {
        ViewModelProvider(activity as ViewModelStoreOwner).get(ProductViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val listView =
            inflater.inflate(R.layout.product_list_fragment, container, false) as RecyclerView
        listView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
        model.products.observe(viewLifecycleOwner, Observer { productList ->
            listView.adapter = ProductListAdapter(productList)    // THIS LINE IS PART OF THE ERROR
        })
        return listView
    }

    private fun selectItem(product: Product) {
        model.select(product)

        fragmentManager?.beginTransaction()?.replace(R.id.fragment, ProductDetailsFragment())
            ?.commit()
    }


    private inner class ProductListAdapter(var productList: List<Product>) :
        RecyclerView.Adapter<ProductListAdapter.ViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.product_list_item, parent, false)
            return ViewHolder(view)
        }

        override fun getItemCount(): Int {
            return productList.size
        }

        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val product = productList[position]
            holder.productName.text = product.title

            holder.itemView.setOnClickListener {
                selectItem(product)
            }
        }

        private inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
            val productName: TextView = view.findViewById(R.id.productName)
        }
    }
}

ProductViewModel.kt:

class ProductViewModel : ViewModel() {
    val products: LiveData<List<Product>> by lazy {
        MutableLiveData<List<Product>>().also {
            val productList = arrayListOf<Product>()
            Repository.getAllProducts()?.addOnSuccessListener {products ->
                products.forEach { product ->
                    productList.add(product.toObject(Product::class.java))
                }
                it.value = productList  // THIS LINE IS CAUSING AN ERROR
            }
        }
    }
...

Repository.kt:

object Repository {
    private val db = FirebaseFirestore.getInstance()

    private val productCollection: CollectionReference?
        get() {
            val user = Authenticator.user
            if (user != null) {
                return db.collection(USERS).document(user.uid).collection(COLLECTION)
            }
            return null
        }

    fun getAllProducts(): Task<QuerySnapshot>? {
        return productCollection?.get()
    }
...

这是我得到的错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'boolean androidx.recyclerview.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
        at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeAndRecycleAllViews(RecyclerView.java:10340)
        at androidx.recyclerview.widget.RecyclerView.removeAndRecycleViews(RecyclerView.java:1179)
        at androidx.recyclerview.widget.RecyclerView.setAdapterInternal(RecyclerView.java:1202)
        at androidx.recyclerview.widget.RecyclerView.setAdapter(RecyclerView.java:1161)
        at .ProductListFragment$onCreateView$1.onChanged(ProductListFragment.kt:35)
        at .ProductListFragment$onCreateView$1.onChanged(ProductListFragment.kt:22)
        at androidx.lifecycle.LiveData.considerNotify(LiveData.java:131)
        at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:149)
        at androidx.lifecycle.LiveData.setValue(LiveData.java:307)
        at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
        at .ProductViewModel$products$2$1$1.onSuccess(ProductViewModel.kt:17)
        at .ProductViewModel$products$2$1$1.onSuccess(ProductViewModel.kt:9)
        at com.google.android.gms.tasks.zzn.run(Unknown Source)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6682)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

数据库具有该集合的三个条目,但是存储库传递给onSuccess函数的值是一个空列表(不是null)。我在这里有两个问题:

  1. 为什么存储库将返回一个空列表而不是三个项目?
  2. 导致崩溃的NPE来自哪里?
android kotlin google-cloud-firestore viewmodel android-livedata
1个回答
0
投票

viemodelrecyclerview而不是onViewCreated中的onCreateView调用>

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
       //view model and recyclerview
    }

//活动!

ViewModelProvider(activity!!.get(ProductViewModel::class.java)
© www.soinside.com 2019 - 2024. All rights reserved.