У меня есть приложение, которое отображает список продуктов во фрагменте из 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
). У меня здесь два вопроса:
- Почему хранилище возвращает пустой список, а не три элемента?
- Откуда взялся NPE, вызвавший кр sh?