无法在像 playstore 这样的嵌套回收器视图中检索数据
Unable to retrieve data in nested recycler view like playstore
在从 server.I 成功检索并解析 parent recyclerview 的 title
但无法显示水平 recyclerview 后,我试图在嵌套的 recyclerview 中显示数据,例如 play store这是一个 child 布局。
我在视图模型实例化时在 CategortAdapter.kt
中遇到错误,它在下面的 ViewModelProvider(context)
下显示红线:
val viewModel = ViewModelProvider(context).get(CatImagesViewModel::class.java)
以下是我的 JSON 回复:
{
"status": "200",
"message": "Success",
"result": [
{
"_id": "60f516fa846e059e2f19c50c",
"category": "Shirts",
"sku": [
{
"name": "Oxford shirt",
"brand": "John players",
"price": "25",
"color": "Blue",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi1.jpg?alt=media&token=64779194-e3b5-484f-a610-c9a20648b64c"
},
{
"name": "Buttoned down",
"brand": "Gap originals",
"price": "45",
"color": "Pink",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi2.jpg?alt=media&token=0b207b90-f1bc-4771-b877-809648e6bdc1"
},
{
"name": "Collared",
"brand": "Arrow",
"price": "30",
"color": "White",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi3.jpg?alt=media&token=2c1bb3f8-e739-4f09-acbc-aa11fed795e3"
},
{
"name": "Printed",
"brand": "John players",
"price": "30",
"color": "Olive green",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi4.jpg?alt=media&token=666f94bf-4769-44fe-a909-3c81ca9262f7"
},
{
"name": "Hoodie",
"brand": "Levis",
"price": "44",
"color": "Yellow",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi5.jpg?alt=media&token=65fccef4-a882-4278-b5df-f00eb2785bf1"
}
]
},
{
"_id": "60f51c37846e059e2f19c50f",
"category": "Shoes",
"sku": [
{
"name": "Sneakers",
"brand": "Puma",
"price": "35",
"color": "Black and white",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho1.jpg?alt=media&token=d078988d-9e85-4313-bb4a-c9d46e09f0b9"
},
{
"name": "Running shoe",
"brand": "Nike",
"price": "99",
"color": "Multicolor",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho2.jpg?alt=media&token=ed2e7387-3cf6-44df-9f7d-69843eb0bcdf"
},
{
"name": "Yezzy",
"brand": "Adidas",
"price": "349",
"color": "Gray",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho3.jpg?alt=media&token=2c37ef76-37bb-4bdd-b36c-dea32857291f"
},
{
"name": "Sneakers",
"brand": "Puma",
"price": "79",
"color": "Black",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho4.jpg?alt=media&token=4acd763e-8b93-47cd-ba45-92f34af4cf83"
},
{
"name": "Joyride running",
"brand": "Nike",
"price": "80",
"color": "White",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho5.jpg?alt=media&token=e3780dcc-52cb-49d5-9791-e0a44870716c"
}
]
}
]
}
在垂直的 parent 回收器视图中,我想显示标题 category
,如 JSON 响应和水平回收器视图中的 sku
所示。
在 child 回收站视图中,我只想显示 sku
数组下的图像。
下面是我的代码:
ApiService.kt
interface ApiService {
@GET("getProducts")
suspend fun getCategories(): Response<Product>
@GET("getProducts")
suspend fun getCatImg(): Response<Product>
}
Product.kt
data class Product(
val message: String,
val result: List<Result>,
val status: String
)
Result.kt
data class Result(
val _id: String,
val category: String,
val sku: List<Sku>
)
Sku.kt
data class Sku(
val brand: String,
val color: String,
val img: String,
val name: String,
val price: String
)
parent_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/catTitle"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="#345"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/childRecycler"
android:layout_below="@+id/catTitle"
android:layout_marginTop="8dp"/>
</RelativeLayout>
child_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:layout_width="200dp"
android:layout_height="200dp"
app:cardCornerRadius="3dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/img"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
在下面的适配器中,我正在获取类别标题和 child 回收站视图,因为我已成功检索到标题但无法解析回收站视图:
CategoryAdapter.kt
class CategoryAdapter(private val context: Context,private val categories:List<Result>): RecyclerView.Adapter<CategoryAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return
ViewHolder(ParentRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val model = categories[position]
holder.binding.catTitle.text = model.category
holder.binding.childRecycler.setHasFixedSize(true)
holder.binding.childRecycler.layoutManager = LinearLayoutManager(context)
val viewModel = ViewModelProvider(context).get(CatImagesViewModel::class.java)
}
override fun getItemCount(): Int {
return categories.size
}
class ViewHolder(val binding:ParentRowBinding): RecyclerView.ViewHolder(binding.root)
}
CatImagesViewModel.kt
class CatImagesViewModel: ViewModel() {
private var catImageList:MutableLiveData<List<List<Sku>>> = MutableLiveData()
fun getCatImg(): LiveData<List<List<Sku>>>{
viewModelScope.launch(Dispatchers.IO) {
val retrofit = RetrofitClient.getRetrofitClient().create(ApiService::class.java)
val response = retrofit.getCatImg()
if(response.isSuccessful){
val skus: MutableList<List<Sku>> = mutableListOf()
val cnt = response.body()!!.result.size
for(i in 0 until cnt){
skus.add(response.body()!!.result[i].sku)
}
catImageList.postValue(skus)
}
}
return catImageList
}
}
下面是在child回收站视图中解析图像的适配器,它是水平的:
CatImgAdapter.kt
class CatImgAdapter(private val context: Context,private val imgList:List<Sku>): RecyclerView.Adapter<CatImgAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(ChildRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val model = imgList[position]
Glide.with(context).load(model.img).into(holder.binding.img)
}
override fun getItemCount(): Int {
return imgList.size
}
data class ViewHolder(val binding:ChildRowBinding): RecyclerView.ViewHolder(binding.root)
}
下面是 ViewModel
用于获取垂直回收站视图的类别标题:
CategoriesViewModel.kt
class CategoriesViewModel: ViewModel() {
private var categoryList: MutableLiveData<List<Result>> = MutableLiveData()
fun getAllCategory(): LiveData<List<Result>> {
viewModelScope.launch(Dispatchers.IO) {
val retrofit = RetrofitClient.getRetrofitClient().create(ApiService::class.java)
val response = retrofit.getCategories()
if (response.isSuccessful) {
categoryList.postValue(response.body()!!.result)
}
}
return categoryList
}
}
有人告诉我我做错了什么或实现所需布局的最佳方法。
您不应该在 recyclerview adapter
中实例化您的 ViewModel
。相反,您需要将数据传递给您的 recyclerview adapter
.
您应该观察 View
(activity
或 fragment
)中的 LiveData
,然后将此数据(List<Result>
此处)传递给您的recyclerview adapter
。 ViewModel
只能在这些 Views
.
中使用
如果您需要更多解释,请告诉我,我会尽量详细解释:)
编辑
我也注意到CatImagesViewModel
你有
if(response.isSuccessful){
val cnt = response.body()!!.result.size
for(i in 0 until cnt){
catImageList.postValue(response.body()!!.result[i].sku)
}
}
postvalue
会将当前 result
的 sku
设置为 MutableLiveData
,这意味着您将拥有 sku
(List<Sku>
) 仅来自 1 category
,因为每次迭代都会丢弃前一个。
你想做的是,
class CatImagesViewModel: ViewModel() {
private var catImageList:MutableLiveData<List<List<<Sku>>> = MutableLiveData()
fun getCatImg(): LiveData<List<List<Sku>>>{
viewModelScope.launch(Dispatchers.IO) {
val retrofit = RetrofitClient.getRetrofitClient().create(ApiService::class.java)
val response = retrofit.getCatImg()
if(response.isSuccessful){
val skus: MutableList<List<List<Sku>>> = mutableListOf()
val cnt = response.body()!!.result.size
for(i in 0 until cnt){
skus.add(response.body()!!.result[i].sku)
}
catImageList.postValue(skus)
}
}
return catImageList
}
}
最终更新
好的,这是你需要在嵌套的recyclerview中加载项目的代码,如果这些类的名称与你的不同,那么只需创建一个新项目并添加此代码以供参考,我附上了下面应用程序的工作屏幕截图作为提示,希望它现在可以为您解决所有问题:)
MainActivity.kt
class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.getResult()
val adapter = ParentAdapter(this)
recyclerview_parent.adapter = adapter
viewModel.data.observe(this, {
adapter.setData(it)
})
}
}
MainViewModel.kt
class MainViewModel : ViewModel() {
private val service = RetrofitHelper().retrofit.create(ApiService::class.java)
private val _data: MutableLiveData<List<Result>> = MutableLiveData()
val data: LiveData<List<Result>> get() = _data
fun getResult() {
viewModelScope.launch {
val res = service.getProducts()
_data.postValue(res.body()?.result)
}
}
}
ApiService.kt
interface ApiService {
@GET("getProducts")
suspend fun getProducts(): Response<Product>
}
ParentAdapter.kt
class ParentAdapter(
private val context: Context
): RecyclerView.Adapter<ParentAdapter.ParentViewHolder>() {
private var data: List<Result>? = null
inner class ParentViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
fun setData(data: List<Result>) {
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParentViewHolder {
return ParentViewHolder(
LayoutInflater.from(context)
.inflate(R.layout.item_parent,parent,false)
)
}
override fun onBindViewHolder(holder: ParentViewHolder, position: Int) {
val item = data?.get(position)
if (item != null) {
holder.itemView.category_title.text = item.category
val adapter = ChildAdapter(context)
adapter.setData(item.sku)
holder.itemView.recyclerview_child.adapter = adapter
}
}
override fun getItemCount(): Int {
return data?.size ?: 0
}
}
ChildAdapter.kt
class ChildAdapter(
private val context: Context
) : RecyclerView.Adapter<ChildAdapter.ChildViewHolder>() {
private var data: List<Sku>? = null
inner class ChildViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
fun setData(data: List<Sku>) {
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChildViewHolder {
return ChildViewHolder(
LayoutInflater.from(context)
.inflate(R.layout.item_child, parent, false)
)
}
override fun onBindViewHolder(holder: ChildViewHolder, position: Int) {
val item = data?.get(position)
if (item != null) {
holder.itemView.label.text = item.name
Glide.with(context)
.load(item.img)
.transition(DrawableTransitionOptions.withCrossFade())
.into(holder.itemView.image)
}
}
override fun getItemCount(): Int {
return data?.size ?: 0
}
}
RetrofitHelper.kt
class RetrofitHelper {
val retrofit = Retrofit.Builder()
.baseUrl("https://koovs18.herokuapp.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
item_parent.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/category_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Category Title"
android:layout_marginStart="4dp"
android:layout_marginTop="8dp"
android:textSize="24sp"
android:textColor="@color/black"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_child"/>
</LinearLayout>
item_child.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
android:layout_width="150dp"
android:layout_height="160dp"
android:layout_margin="4dp"/>
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Product Label"
android:gravity="center"
android:textSize="16sp"
android:textColor="@color/black"
android:padding="4dp"/>
</LinearLayout>
Dependencies you would need in build.gradle
def coroutines_version = "1.4.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
def lifecycle_version = "2.3.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
def retrofit_version = "2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'
implementation "androidx.activity:activity-ktx:1.2.4"
在从 server.I 成功检索并解析 parent recyclerview 的 title
但无法显示水平 recyclerview 后,我试图在嵌套的 recyclerview 中显示数据,例如 play store这是一个 child 布局。
我在视图模型实例化时在 CategortAdapter.kt
中遇到错误,它在下面的 ViewModelProvider(context)
下显示红线:
val viewModel = ViewModelProvider(context).get(CatImagesViewModel::class.java)
以下是我的 JSON 回复:
{
"status": "200",
"message": "Success",
"result": [
{
"_id": "60f516fa846e059e2f19c50c",
"category": "Shirts",
"sku": [
{
"name": "Oxford shirt",
"brand": "John players",
"price": "25",
"color": "Blue",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi1.jpg?alt=media&token=64779194-e3b5-484f-a610-c9a20648b64c"
},
{
"name": "Buttoned down",
"brand": "Gap originals",
"price": "45",
"color": "Pink",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi2.jpg?alt=media&token=0b207b90-f1bc-4771-b877-809648e6bdc1"
},
{
"name": "Collared",
"brand": "Arrow",
"price": "30",
"color": "White",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi3.jpg?alt=media&token=2c1bb3f8-e739-4f09-acbc-aa11fed795e3"
},
{
"name": "Printed",
"brand": "John players",
"price": "30",
"color": "Olive green",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi4.jpg?alt=media&token=666f94bf-4769-44fe-a909-3c81ca9262f7"
},
{
"name": "Hoodie",
"brand": "Levis",
"price": "44",
"color": "Yellow",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/shi5.jpg?alt=media&token=65fccef4-a882-4278-b5df-f00eb2785bf1"
}
]
},
{
"_id": "60f51c37846e059e2f19c50f",
"category": "Shoes",
"sku": [
{
"name": "Sneakers",
"brand": "Puma",
"price": "35",
"color": "Black and white",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho1.jpg?alt=media&token=d078988d-9e85-4313-bb4a-c9d46e09f0b9"
},
{
"name": "Running shoe",
"brand": "Nike",
"price": "99",
"color": "Multicolor",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho2.jpg?alt=media&token=ed2e7387-3cf6-44df-9f7d-69843eb0bcdf"
},
{
"name": "Yezzy",
"brand": "Adidas",
"price": "349",
"color": "Gray",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho3.jpg?alt=media&token=2c37ef76-37bb-4bdd-b36c-dea32857291f"
},
{
"name": "Sneakers",
"brand": "Puma",
"price": "79",
"color": "Black",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho4.jpg?alt=media&token=4acd763e-8b93-47cd-ba45-92f34af4cf83"
},
{
"name": "Joyride running",
"brand": "Nike",
"price": "80",
"color": "White",
"img": "https://firebasestorage.googleapis.com/v0/b/koovs-1ff31.appspot.com/o/sho5.jpg?alt=media&token=e3780dcc-52cb-49d5-9791-e0a44870716c"
}
]
}
]
}
在垂直的 parent 回收器视图中,我想显示标题 category
,如 JSON 响应和水平回收器视图中的 sku
所示。
在 child 回收站视图中,我只想显示 sku
数组下的图像。
下面是我的代码:
ApiService.kt
interface ApiService {
@GET("getProducts")
suspend fun getCategories(): Response<Product>
@GET("getProducts")
suspend fun getCatImg(): Response<Product>
}
Product.kt
data class Product(
val message: String,
val result: List<Result>,
val status: String
)
Result.kt
data class Result(
val _id: String,
val category: String,
val sku: List<Sku>
)
Sku.kt
data class Sku(
val brand: String,
val color: String,
val img: String,
val name: String,
val price: String
)
parent_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/catTitle"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="#345"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/childRecycler"
android:layout_below="@+id/catTitle"
android:layout_marginTop="8dp"/>
</RelativeLayout>
child_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:layout_width="200dp"
android:layout_height="200dp"
app:cardCornerRadius="3dp"
app:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/img"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
在下面的适配器中,我正在获取类别标题和 child 回收站视图,因为我已成功检索到标题但无法解析回收站视图:
CategoryAdapter.kt
class CategoryAdapter(private val context: Context,private val categories:List<Result>): RecyclerView.Adapter<CategoryAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return
ViewHolder(ParentRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val model = categories[position]
holder.binding.catTitle.text = model.category
holder.binding.childRecycler.setHasFixedSize(true)
holder.binding.childRecycler.layoutManager = LinearLayoutManager(context)
val viewModel = ViewModelProvider(context).get(CatImagesViewModel::class.java)
}
override fun getItemCount(): Int {
return categories.size
}
class ViewHolder(val binding:ParentRowBinding): RecyclerView.ViewHolder(binding.root)
}
CatImagesViewModel.kt
class CatImagesViewModel: ViewModel() {
private var catImageList:MutableLiveData<List<List<Sku>>> = MutableLiveData()
fun getCatImg(): LiveData<List<List<Sku>>>{
viewModelScope.launch(Dispatchers.IO) {
val retrofit = RetrofitClient.getRetrofitClient().create(ApiService::class.java)
val response = retrofit.getCatImg()
if(response.isSuccessful){
val skus: MutableList<List<Sku>> = mutableListOf()
val cnt = response.body()!!.result.size
for(i in 0 until cnt){
skus.add(response.body()!!.result[i].sku)
}
catImageList.postValue(skus)
}
}
return catImageList
}
}
下面是在child回收站视图中解析图像的适配器,它是水平的:
CatImgAdapter.kt
class CatImgAdapter(private val context: Context,private val imgList:List<Sku>): RecyclerView.Adapter<CatImgAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(ChildRowBinding.inflate(LayoutInflater.from(parent.context),parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val model = imgList[position]
Glide.with(context).load(model.img).into(holder.binding.img)
}
override fun getItemCount(): Int {
return imgList.size
}
data class ViewHolder(val binding:ChildRowBinding): RecyclerView.ViewHolder(binding.root)
}
下面是 ViewModel
用于获取垂直回收站视图的类别标题:
CategoriesViewModel.kt
class CategoriesViewModel: ViewModel() {
private var categoryList: MutableLiveData<List<Result>> = MutableLiveData()
fun getAllCategory(): LiveData<List<Result>> {
viewModelScope.launch(Dispatchers.IO) {
val retrofit = RetrofitClient.getRetrofitClient().create(ApiService::class.java)
val response = retrofit.getCategories()
if (response.isSuccessful) {
categoryList.postValue(response.body()!!.result)
}
}
return categoryList
}
}
有人告诉我我做错了什么或实现所需布局的最佳方法。
您不应该在 recyclerview adapter
中实例化您的 ViewModel
。相反,您需要将数据传递给您的 recyclerview adapter
.
您应该观察 View
(activity
或 fragment
)中的 LiveData
,然后将此数据(List<Result>
此处)传递给您的recyclerview adapter
。 ViewModel
只能在这些 Views
.
如果您需要更多解释,请告诉我,我会尽量详细解释:)
编辑
我也注意到CatImagesViewModel
你有
if(response.isSuccessful){
val cnt = response.body()!!.result.size
for(i in 0 until cnt){
catImageList.postValue(response.body()!!.result[i].sku)
}
}
postvalue
会将当前 result
的 sku
设置为 MutableLiveData
,这意味着您将拥有 sku
(List<Sku>
) 仅来自 1 category
,因为每次迭代都会丢弃前一个。
你想做的是,
class CatImagesViewModel: ViewModel() {
private var catImageList:MutableLiveData<List<List<<Sku>>> = MutableLiveData()
fun getCatImg(): LiveData<List<List<Sku>>>{
viewModelScope.launch(Dispatchers.IO) {
val retrofit = RetrofitClient.getRetrofitClient().create(ApiService::class.java)
val response = retrofit.getCatImg()
if(response.isSuccessful){
val skus: MutableList<List<List<Sku>>> = mutableListOf()
val cnt = response.body()!!.result.size
for(i in 0 until cnt){
skus.add(response.body()!!.result[i].sku)
}
catImageList.postValue(skus)
}
}
return catImageList
}
}
最终更新
好的,这是你需要在嵌套的recyclerview中加载项目的代码,如果这些类的名称与你的不同,那么只需创建一个新项目并添加此代码以供参考,我附上了下面应用程序的工作屏幕截图作为提示,希望它现在可以为您解决所有问题:)
MainActivity.kt
class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.getResult()
val adapter = ParentAdapter(this)
recyclerview_parent.adapter = adapter
viewModel.data.observe(this, {
adapter.setData(it)
})
}
}
MainViewModel.kt
class MainViewModel : ViewModel() {
private val service = RetrofitHelper().retrofit.create(ApiService::class.java)
private val _data: MutableLiveData<List<Result>> = MutableLiveData()
val data: LiveData<List<Result>> get() = _data
fun getResult() {
viewModelScope.launch {
val res = service.getProducts()
_data.postValue(res.body()?.result)
}
}
}
ApiService.kt
interface ApiService {
@GET("getProducts")
suspend fun getProducts(): Response<Product>
}
ParentAdapter.kt
class ParentAdapter(
private val context: Context
): RecyclerView.Adapter<ParentAdapter.ParentViewHolder>() {
private var data: List<Result>? = null
inner class ParentViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
fun setData(data: List<Result>) {
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParentViewHolder {
return ParentViewHolder(
LayoutInflater.from(context)
.inflate(R.layout.item_parent,parent,false)
)
}
override fun onBindViewHolder(holder: ParentViewHolder, position: Int) {
val item = data?.get(position)
if (item != null) {
holder.itemView.category_title.text = item.category
val adapter = ChildAdapter(context)
adapter.setData(item.sku)
holder.itemView.recyclerview_child.adapter = adapter
}
}
override fun getItemCount(): Int {
return data?.size ?: 0
}
}
ChildAdapter.kt
class ChildAdapter(
private val context: Context
) : RecyclerView.Adapter<ChildAdapter.ChildViewHolder>() {
private var data: List<Sku>? = null
inner class ChildViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
fun setData(data: List<Sku>) {
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChildViewHolder {
return ChildViewHolder(
LayoutInflater.from(context)
.inflate(R.layout.item_child, parent, false)
)
}
override fun onBindViewHolder(holder: ChildViewHolder, position: Int) {
val item = data?.get(position)
if (item != null) {
holder.itemView.label.text = item.name
Glide.with(context)
.load(item.img)
.transition(DrawableTransitionOptions.withCrossFade())
.into(holder.itemView.image)
}
}
override fun getItemCount(): Int {
return data?.size ?: 0
}
}
RetrofitHelper.kt
class RetrofitHelper {
val retrofit = Retrofit.Builder()
.baseUrl("https://koovs18.herokuapp.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
item_parent.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/category_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Category Title"
android:layout_marginStart="4dp"
android:layout_marginTop="8dp"
android:textSize="24sp"
android:textColor="@color/black"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_child"/>
</LinearLayout>
item_child.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
android:layout_width="150dp"
android:layout_height="160dp"
android:layout_margin="4dp"/>
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Product Label"
android:gravity="center"
android:textSize="16sp"
android:textColor="@color/black"
android:padding="4dp"/>
</LinearLayout>
Dependencies you would need in build.gradle
def coroutines_version = "1.4.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
def lifecycle_version = "2.3.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
def retrofit_version = "2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'
implementation "androidx.activity:activity-ktx:1.2.4"