0

I have an app that displays a list of products in a fragment from the MainActivity. The list of items is read using a ViewModel via a Repository from a Firestore database.

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()
    }
...

Here is the error I am getting:

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)

The database has three entries for that collection, but the value passed by the Repository to the onSuccess function is an empty list (not null). I have two questions here:

  1. Why would the repository return an empty list and not the three items?
  2. Where does the NPE that caused the crash come from?
2
  • At which particular line of code are you getting that error? Commented Feb 25, 2020 at 10:09
  • The lines of the error are marked by comments in the code Commented Feb 25, 2020 at 18:43

1 Answer 1

0

viemodel and recyclerview call in onViewCreated instead of onCreateView

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

// activity!!

ViewModelProvider(activity!!.get(ProductViewModel::class.java)
Sign up to request clarification or add additional context in comments.

1 Comment

That did not fix it. I am still getting the same error, but now it's coming from onViewCreated

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.