【问题标题】:FirestoreRecyclerAdapter getItemCount() always returns 0FirestoreRecyclerAdapter getItemCount() 总是返回 0
【发布时间】:2020-02-29 08:26:23
【问题描述】:

这是我的适配器类代码:

class SearchPeopleAdapter(user: FirestoreRecyclerOptions<User>) :
    FirestoreRecyclerAdapter<User, SearchPeopleAdapter.ViewHolder>(user) {

    private var mUser : FirestoreRecyclerOptions<User>? = null

    private var mOptions: FirestoreRecyclerOptions<User>? = null
    private var mSnapshots: ObservableSnapshotArray<User>? = null

    init {
        mUser = user
    }

    fun firestoreRecyclerAdapter(user: FirestoreRecyclerOptions<User>?) {
        mOptions = user
        mSnapshots = user!!.snapshots
        if (mOptions!!.owner != null) {
            mOptions!!.owner!!.lifecycle.addObserver(this)
        }
    }

    override fun startListening() {
        if (!mSnapshots!!.isListening(this)) {
            mSnapshots!!.addChangeEventListener(this);
        }
    }

    override fun stopListening() {
        mSnapshots!!.removeChangeEventListener(this)
        notifyDataSetChanged()
    }

    //Inflate the xml
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.search_people_list_item, parent, false))
    }

    //Bind every dataView to the xml based on the Int value
    override fun onBindViewHolder(viewHolder: ViewHolder, holderNumber: Int, user: User) {
        viewHolder.apply {
            itemView.search_people_person_list_name.text = user.Name
            itemView.search_people_person_username.text = user.UserName
        }
        viewHolder.bind(user)
    }

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

    //Adds functionality to each View (aka ViewHolder) which is every person downloaded
    inner class ViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView!!), View.OnClickListener {
        //We are downloading User Objects so this Variable will be assigned to the UserObject downloaded
        var currentUser : User? = null
        //When the class is initiated this function is called which sets an OnClickListener to each View
        init {
            itemView!!.setOnClickListener(this)
        }

        //The Data from the Object is used to Populate the TextViews
        fun bind(model: User) {
            currentUser = model
            itemView.search_people_person_list_name.text = model.Name
            itemView.search_people_person_username.text = model.UserName

            //If the user has set a profilePhoto then download & populate it with Glide
            if ( model.ProfilePhotoChosen ) {
                CompanionObjects.getPersonProfilePhotoStorageRef(model.Uid).downloadUrl.addOnSuccessListener {
                    val downloadUrl = it.toString()
                    Glide.with(itemView)
                        .load(downloadUrl)
                        .into(itemView.search_people_list_profile_image)
                }.addOnFailureListener {
                    Timber.i("unable to retrieve your profile photo")
                }
            }
            //Clear the View with the Glide.with(View).clear() method as the view will be reused and the photo
            //might also get reused unnecessarily
            else {
                Glide.with(itemView).clear(itemView.search_people_list_profile_image)
            }

        }

        //The onClick function is called when the View is clicked, in this case we are starting
        // an Intent with the Intent Extra of userId to the PersonProfile Activity
        // which will check for the IntentExtras and Populate the elements
        override fun onClick(v: View?) {
            val userId = currentUser!!.Uid
            Timber.i("The click is $userId")
            val intent = Intent(v!!.context, PersonProfileActivity::class.java)
            intent.putExtra(CompanionObjects.USER_ID_INTENT_EXTRA, userId)
            v.context.startActivity(intent)
        }

    }

} 

这里是Activity类中的2个方法,尽管调用了onStart和onStop方法,itemCount方法总是返回0


    override fun onStop() {
        adapter!!.stopListening()
        super.onStop()
    }

    //Retrieves data from Firestore and assigns the retrieved data to the search People Adapter
    private fun retrieveDataFromFirestore(searchQuery : String) {

        mFirestore = FirebaseFirestore.getInstance()
        //Assigns the Collection Name from which needs to be queried
        //the where conditions ensure to query a userDocument whose userName starts with the query entered in the searchField
        val userNameQuery = mFirestore.collection(CompanionObjects.USERS_COLLECTION_NAME)
            .whereGreaterThanOrEqualTo("userName", searchQuery)
            .whereLessThanOrEqualTo("userName", "$searchQuery\uF7FF")

        //Assigns the query to the User Objects that are related to Firestore
        users = FirestoreRecyclerOptions.Builder<User>()
            .setQuery(userNameQuery, User::class.java)
            .build()

        //Assigns the Firestore queried data to the search People Adapter
        adapter = SearchPeopleAdapter(users!!)
        registerAdapterObserver()
        adapter!!.firestoreRecyclerAdapter(users!!)
        adapter!!.startListening()
        search_people_list.setHasFixedSize(true)
        search_people_list.hasFixedSize()
        search_people_list.layoutManager = LinearLayoutManager(this)
        search_people_list.adapter = adapter
        persistSearchQueryString(searchQuery)

    }

当我在 Activity 类中调用 getItemCount 方法时。即使适配器确实持有视图,它也总是返回 0。如何检索适配器中的确切计数

【问题讨论】:

    标签: android firebase kotlin android-recyclerview google-cloud-firestore


    【解决方案1】:

    请确保 mSnapshots = user!!.snapshots 生成项目。

    【讨论】:

      【解决方案2】:

      adapter!!.firestoreRecyclerAdapter(users!!) 中添加项目后,在fun retrieveDataFromFirestore(searchQuery : String) 中,您没有通知 RecyclerView 进行更新。

      所以,别忘了打电话

      adapter!!.notifyDataSetChanged();
      

      您的代码可能如下所示:

      private fun retrieveDataFromFirestore(searchQuery : String) {
      
          mFirestore = FirebaseFirestore.getInstance()
          //Assigns the Collection Name from which needs to be queried
          //the where conditions ensure to query a userDocument whose userName starts with the query entered in the searchField
          val userNameQuery = mFirestore.collection(CompanionObjects.USERS_COLLECTION_NAME)
              .whereGreaterThanOrEqualTo("userName", searchQuery)
              .whereLessThanOrEqualTo("userName", "$searchQuery\uF7FF")
      
          //Assigns the query to the User Objects that are related to Firestore
          users = FirestoreRecyclerOptions.Builder<User>()
              .setQuery(userNameQuery, User::class.java)
              .build()
      
          //Assigns the Firestore queried data to the search People Adapter
          adapter = SearchPeopleAdapter(users!!)
          registerAdapterObserver()
          adapter!!.firestoreRecyclerAdapter(users!!)
          adapter!!.startListening()
          adapter!!.notifyDataSetChanged();  //<------- Add this line---------
          search_people_list.setHasFixedSize(true)
          search_people_list.hasFixedSize()
          search_people_list.layoutManager = LinearLayoutManager(this)
          search_people_list.adapter = adapter
          persistSearchQueryString(searchQuery)
      
      }
      

      【讨论】:

      • 还是不行,加上notifyDataSetChanged()还是返回0
      • 只要确保fun firestoreRecyclerAdapter user!!.snapshots 中有项目并且计数不为零
      • 它确实返回了,我可以看到 recyclerView 填充了数据,但 itemCount 显示为 0。我正在尝试 registerAdapterDataObserver 方法,但只有在查询时有项目时才有效,我想知道什么时候查询返回 0,因此我可以向用户显示“找不到任何东西”等文本.....
      【解决方案3】:

      好的,我解决了,代码如下:

      private fun retrieveDataFromFirestore(searchQuery : String) {
      
      mFirestore = FirebaseFirestore.getInstance()
      
       //Assigns the Collection Name from which needs to be queried
              //the where conditions ensure to query a userDocument whose userName 
       starts with the query entered in the searchField
              val userNameQuery = mFirestore.collection(CompanionObjects.USERS_COLLECTION_NAME)
                  .whereGreaterThanOrEqualTo(userName, searchQuery.toLowerCase())
                  .whereLessThanOrEqualTo(userName, "${searchQuery.toLowerCase()}\uF7FF")
      
              //Assign the Query to the user variable
              users = FirestoreRecyclerOptions.Builder<User>()
                  .setQuery(userNameQuery, User::class.java)
                  .build()
      
      //Assigns the Firestore queried data to the search People Adapter
          adapter = object : SearchPeopleAdapter(users!!) {
              //Need to create a class Body because it is open and this gives
              //option to override its onDataChanged method in the Activity rather than in its adapter class
              override fun onDataChanged() {
                  if ( itemCount == 0 ) {
                      search_people_list.visibility = View.INVISIBLE
                      retrieving_progress.visibility = View.INVISIBLE
                      empty_search_users_text.visibility = View.VISIBLE
                      //If was not searching with name field then prompt search with name field
                      if ( !searchingWithNameField ) {
                          //Code to add formatting options to the text like underline it
                          val content = SpannableString(getString(R.string.search_with_name_instead))
                          content.setSpan(UnderlineSpan(), 0, content.length, 0)
                          change_search_field_text.text = content
                      } else
                      //If was not searching with username field then prompt search with username field
                      {
                          //Code to add formatting options to the text like underline it
                          val content = SpannableString(getString(R.string.search_with_username_instead))
                          content.setSpan(UnderlineSpan(), 0, content.length, 0)
                          change_search_field_text.text = content
                      }
                      change_search_field_text.visibility = View.VISIBLE
                  } else {
                      //The adapter count is not 0 so show the recyclerView and hide the progress bar, emptyText, Change Search field Text etc.
                      search_people_list.visibility = View.VISIBLE
                      retrieving_progress.visibility = View.INVISIBLE
                      empty_search_users_text.visibility = View.INVISIBLE
                      change_search_field_text.visibility = View.INVISIBLE
                      //Should persist only if there is a result from the query ofCourse
                      persistSearchQueryStringAndSearchField(searchQuery)
                  }
              }
          }
      
          adapterCreated = true
          adapter!!.startListening()
          adapter!!.notifyDataSetChanged()
          //Make the progress bar visible and invisible soon as a document is added to the adapter
          registerAdapterObserver()
      
          search_people_list.setHasFixedSize(true)
          search_people_list.hasFixedSize()
          search_people_list.layoutManager = LinearLayoutManager(this)
          search_people_list.adapter = adapter
      

      }

      所以,我所做的是打开适配器类,然后在 Activity 中创建 Adapter 的实例,并在 Activity 中调用 OnDataChanged() 方法,该方法监视 Adapter 中的 itemCount。这样我就可以检索到正确的 adapterCount 值。

      【讨论】:

        猜你喜欢
        • 2017-10-20
        • 1970-01-01
        • 2016-10-22
        • 2015-09-27
        • 2014-03-20
        • 2013-04-13
        • 2013-03-30
        • 2016-07-13
        • 2023-04-09
        相关资源
        最近更新 更多