Recyclerview 数据集在片段开始时不会改变

Posted

技术标签:

【中文标题】Recyclerview 数据集在片段开始时不会改变【英文标题】:Recyclerview dataset does not change on fragment start 【发布时间】:2021-09-26 09:33:04 【问题描述】:

我的片段上有一个 RecyclerView,它从名为 Datasource 的对象中的 ArrayList 获取数据。我想在 Fragment 启动时从 Cloud Firestore 获取新项目,所以我创建了一个名为 getAllProducts 的函数,但是我只能在单击底部导航栏时获取项目。

我几乎尝试了另一个问题的所有答案。我尝试在 onCreate 上重新加载片段,我创建了一个导航动作来片段本身,我在 RecyclerView 适配器中添加了一个从 getAllProducts 函数和 notifyDataSetChanged() 获取数据的函数。我让 getAllProduct 返回数组列表并将其用作 RecyclerView 中的数据。他们都没有工作。

应用启动时:

点击主页时:

这里有相关代码

ProductAdapter.kt

class ProductAdapter(private val productList: ArrayList<ProductItem>):RecyclerView.Adapter<ProductViewHolder>() 

    inner class ProductViewHolder(itemView:View):RecyclerView.ViewHolder(itemView)
        val productImage: ImageView = itemView.findViewById(R.id.productPhoto)
        val productName: TextView = itemView.findViewById(R.id.productName)
        val productRatingBar: RatingBar = itemView.findViewById(R.id.ratingBar2)
        val productRating: TextView = itemView.findViewById(R.id.ratingint)
        val storeName: TextView = itemView.findViewById(R.id.productStoreName)
        val productPrice: TextView = itemView.findViewById(R.id.productPrice)

    



    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder 

        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.product_item,
        parent,false)

        return ProductViewHolder(itemView)
    

    override fun onBindViewHolder(holder: ProductViewHolder, position: Int) 
        val currentItem = productList[position]
        holder.itemView.setOnClickListener 
                view ->
            val action = ProductFragmentDirections.actionProductFragmentToParticularProductFragment2(currentItem)
            view.findNavController().navigate(action)
        
        holder.productImage.setImageResource(currentItem.productImageResource)
        holder.productName.text = currentItem.productName
        holder.productRatingBar.rating = currentItem.productRating.toFloat()
        holder.productRating.text = currentItem.productRating.toString()
        holder.storeName.text = currentItem.storeName
        holder.productPrice.text = currentItem.productPrice.toString().plus("$")

    


    override fun getItemCount() = productList.size

数据源.kt

object Datasource 

    var productList = arrayListOf(

        ProductItem(R.drawable.attach_money,"Sahibinden aerator",4.5,"Serhat Yilmaz",8),
        ProductItem(R.drawable.email,"dus kitapları",3.0,"nerhat Yilmaz",9),
        ProductItem(R.drawable.passwordicon,"h files",1.5,"berhat Yilmaz",77),
        ProductItem(R.drawable.category,"piyasemen",5.0,"xerhat Yilmaz",55),
        ProductItem(R.drawable.attach_money,"Sahibinden sasfaf",1.5,"kerhat Yilmaz",11),
        ProductItem(R.drawable.email,"tus kitapları",3.0,"uerhat Yilmaz",21),
        ProductItem(R.drawable.passwordicon,"f files",1.5,"yerhat Yilmaz",47),
        ProductItem(R.drawable.category,"anguldruva",2.0,"terhat Yilmaz",35),
        ProductItem(R.drawable.email,"tus2 kitaplarım",3.0,"werhat Yilmaz",78),
        ProductItem(R.drawable.passwordicon,"endobox",2.5,"Zerhat Yilmaz",95),
        ProductItem(R.drawable.category,"basplak",4.0,"Ferhat Yilmaz",12)

    )

    fun loadProduct(): ArrayList<ProductItem>
        return productList
    

ProductFragment.kt

class ProductFragment : Fragment() 
    private val myDataset = Datasource.productList
    private val adapter = ProductAdapter(myDataset)



    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 


        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.products_fragment, container, false)
    

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


        val recyclerView: RecyclerView = view.findViewById(R.id.recycler_product)
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(requireActivity())
        FireStoreClass().getAllProducts()
        adapter.notifyDataSetChanged()

    




FireStoreClass().getAllProducts()

private val mFireStore = FirebaseFirestore.getInstance()

fun getAllProducts() 


    mFireStore.collection(Constants.PRODUCTS)
        .get()
        .addOnSuccessListener 
            documents ->
            val list = arrayListOf<ProductItem>()
            for (document in documents)

                val product = document.toObject(ProductItem::class.java)
                list.add(product)

            
            Datasource.productList = list
            
        .addOnFailureListener 
            //Toast.makeText(activity, "Can not get Product! $it.message", Toast.LENGTH_SHORT).show()
        


如果您需要查看:

NavigateActivity.kt

class NavigateActivity : AppCompatActivity() 
    private lateinit var navController: NavController
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_navigate)
        val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.findNavController()
        val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavView)
        bottomNavigationView.setupWithNavController(navController)
        //val action = HomeFragmentDirections


    



mobile_navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mobile_navigation"
    app:startDestination="@id/product_Fragment">

    <fragment
        android:id="@+id/product_Fragment"
        android:name="com.example.TheDentalSupplies.fragments.ProductFragment"
        android:label="products_fragment"
        tools:layout="@layout/products_fragment" >

        <action
            android:id="@+id/action_productFragment_to_particularProductFragment2"
            app:destination="@id/particularProductFragment" />

        <action
            android:id="@+id/action_productFragment_Reload"
            app:destination="@id/product_Fragment" />



    </fragment>
    <fragment
        android:id="@+id/addPostNavActivity"
        android:name="com.example.TheDentalSupplies.AddActivity"
        android:label="addpost"
        tools:layout="@layout/addpost" >
        <action
            android:id="@+id/action_addPostNavActivity_to_productFragment"
            app:destination="@id/product_Fragment" />
    </fragment>

    <activity
        android:id="@+id/userActivity"
        android:name="com.example.TheDentalSupplies.UserActivity"
        android:label="userlayout"
        tools:layout="@layout/userlayout" />
    <fragment
        android:id="@+id/bucketFragment"
        android:name="com.example.TheDentalSupplies.fragments.BucketFragment"
        android:label="bucketlayout"
        tools:layout="@layout/bucketlayout" />
    <fragment
        android:id="@+id/particularProductFragment"
        android:name="com.example.TheDentalSupplies.fragments.ParticularProductFragment"
        android:label="product_layout"
        tools:layout="@layout/product_layout">
        <argument
            android:name="navProductItem"
            app:argType="com.example.TheDentalSupplies.models.ProductItem" />
        <action
            android:id="@+id/action_to_bucketFragment"
            app:destination="@id/bucketFragment" />
        <action
            android:id="@+id/action_to_messageActivity"
            app:destination="@id/messageActivity" />
        <action
            android:id="@+id/action_feedbacksFragment2"
            app:destination="@id/feedbacksFragment2" />
    </fragment>
    <activity
        android:id="@+id/messageActivity"
        android:name="com.example.TheDentalSupplies.MessageActivity"
        android:label="messagelayout"
        tools:layout="@layout/messagelayout" />
    <fragment
        android:id="@+id/feedbacksFragment2"
        android:name="com.example.TheDentalSupplies.fragments.FeedbacksFragment"
        android:label="feedbacks_layout"
        tools:layout="@layout/feedbacks_layout" />

</navigation>

【问题讨论】:

【参考方案1】:

Firebase API 是异步的。因此,任何需要来自数据库的数据的代码都需要在 onSuccess() 方法中,或者从那里调用。在此方法中分配list 对象:

Datasource.productList = list

并不意味着它会立即分配它。数据加载完成后调用 getAllProducts() 方法后始终会触发此代码。因此,您拥有的最佳选择是像这样创建以下对象:

private val myDataset = Datasource.productList
private val adapter = ProductAdapter(myDataset)

onViewCreated里面:

val recyclerView: RecyclerView = view.findViewById(R.id.recycler_product)
recyclerView.layoutManager = LinearLayoutManager(requireActivity())
recyclerView.adapter = adapter
FireStoreClass().getAllProducts()

在 getAllProducts() 方法中,只需执行以下操作:

fun getAllProducts() 
    mFireStore.collection(Constants.PRODUCTS)
        .get()
        .addOnSuccessListener  documents ->
            for (document in documents)
                val product = document.toObject(ProductItem::class.java)
                myDataset.add(product)

            
            adapter.notifyDataSetChanged()
        .addOnFailureListener 
            Toast.makeText(activity, "Can not get Product! $it.message", Toast.LENGTH_SHORT).show()
        


这意味着只有当您从数据库中获得所有必要的数据时才通知适配器。

由于您使用的是 Kotlin,我想您可能也对这篇文章感兴趣:

How to read data from Cloud Firestore using get()?

【讨论】:

非常感谢您的回答。但它仍然不会在应用启动时加载产品。我应该在哪里添加 FireStoreClass().getAllProducts() ?由于我的英语不太好,希望我没有错过您的回答。 哦,对不起,我的错。只是忘了添加 FireStoreClass().getAllProducts() 。请检查我更新的答案。顺便说一句,你的英语真的很好;) 不幸的是它没有工作。应用程序启动时仍然不加载,我不知道为什么。感谢您的回答。祝你有美好的一天:) “它不起作用”没有提供足够的信息,所以我可以进一步帮助您。 onFailure 中的 Toast 消息是否显示了什么?您是否尝试将 onViewCreated 上的四行代码移至 onCreateView 内?是这样的吗? 当我向 onCreateView 添加四行时,我得到了这个错误 java.lang.IllegalStateException: Fragment ProductFragment1336db9 (0bd85290-7fbe-4464-89cf-046e81c43e07 id=0x7f0a0162) did not return a View来自 onCreateView() 或在 onCreateView() 之前调用。【参考方案2】:

我终于找到了一种方法,虽然不是最好的解决方案,但却能胜任。

常量.kt

object Constants 
    var REPEAT:Int = 0

在 ProductFragment.kt 中

if (Constants.REPEAT < 1)
            Constants.REPEAT = Constants.REPEAT + 1
            Handler(Looper.getMainLooper()).postDelayed(
                Toast.makeText(requireContext(),"got here", Toast.LENGTH_SHORT).show()
                val bottom = view.findNavController()
                bottom.navigate(R.id.action_product_Fragment_self)
            ,5000)
        

【讨论】:

将操作延迟 5000 毫秒根本不是解决方案。用 5001 毫秒读取数据怎么样?

以上是关于Recyclerview 数据集在片段开始时不会改变的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView 内容未使用片段父级的全宽

当另一个片段中的数据发生更改时,如何刷新一个片段中的 RecyclerView

如何在单击 RecyclerView 项目时从一个片段移动到另一个片段

当sqlite android片段中的数据更改或删除时如何刷新recyclerview?

更新片段中的 RecyclerView

scrollToPosition(),使用片段更新RecyclerView时