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 项目时从一个片段移动到另一个片段