gpt4 book ai didi

android - 我的 RecyclerView 没有得到适当的通知

转载 作者:行者123 更新时间:2023-11-30 00:20:18 25 4
gpt4 key购买 nike

我有一个 RecyclerView Activity 和一个 ViewModel 类。该 Activity 调用 ViewModel 中的一个方法,该方法使用 Web 服务,它还观察一个 LiveData 字段。每次该方法从 Web 服务返回一个项目时,它都会将其设置为 LiveData,因此 Activity 中的观察者会收到通知,因此所有项目都会进入 RecyclerView。正如我在日志和 UI 中看到的那样,可以保证此流程正常工作。

当我在使用 Web 服务的方法中使用 Thread.slepp(500) 进行延迟时,问题就出现了。

它不是将一个项目放入 RecyclerView 然后等待 500 毫秒再放入另一个,而是等待 500 毫秒 * numberOfItems 然后将它们全部绘制在一起。

我可以保证 ViewModel 和 LiveData 设置没有问题,因为日志按预期工作,它打印创建的项目的标题,等待 500 毫秒,打印下一个。所以问题只在于适配器以及如何仅在方法调用完成后才通知它。

我的问题是每次调用观察者时如何通知适配器?

这是我对这三个类的实现:

食谱列表

class RecipeList : LifecycleActivity() {

var recipeList: MutableList<Recipe> = mutableListOf()
var adapter: RecipeAdapter? = null
var viewModel: RecipeViewModel? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recipe_list)

val ingredients = intent.getStringExtra("ingredients")
val term = intent.getStringExtra("term")


viewModel = ViewModelProviders.of(this).get(RecipeViewModel::class.java)


val url = "http://www.recipepuppy.com/api/?i=${ingredients}onions,garlic&q=${term}"


val layoutManager = LinearLayoutManager(this)
adapter = RecipeAdapter(this, recipeList)

rec_recycler_id.layoutManager = layoutManager
rec_recycler_id.adapter = adapter



subscribe()


viewModel?.getRecipe(url)


}

fun subscribe() {

val observer = Observer<Recipe> { recipe ->


if (recipe != null) {

Log.d("mike", "subscribe ${recipe?.title} ")


recipeList.add(recipe)
adapter?.notifyDataSetChanged()


}

}

viewModel?.mRecipe?.observe(this, observer)

}


}

RecipeViewModel

class RecipeViewModel(application: Application): AndroidViewModel(application) {

var recipes: MutableLiveData<MutableList<Recipe>>? = MutableLiveData<MutableList<Recipe>>()
var mRecipe: MutableLiveData<Recipe> = MutableLiveData()





fun getRecipe(url:String){

val requestQueue = Volley.newRequestQueue(this.getApplication())


val recipeRequest = JsonObjectRequest(Request.Method.GET,url,
Response.Listener {
response: JSONObject ->
try {

val results = response.getJSONArray("results")

for( i in 0..results.length()-1){
var recipeObj = results.getJSONObject(i)

var title = recipeObj.getString("title")
var link = recipeObj.getString("href")
var thumbnail = recipeObj.getString("thumbnail")
var ingredients = recipeObj.getString("ingredients")

var recipe = Recipe(title,ingredients,thumbnail,link)


mRecipe.value = recipe
Log.d("mike",title)

Thread.sleep(200)

}


}catch (e: JSONException){
e.printStackTrace()
}
},
Response.ErrorListener {
error: VolleyError? ->
try{
Log.d("error",error.toString())

}catch (e: JSONException){
e.printStackTrace()
}
})


requestQueue?.add(recipeRequest)

}

RecipeAdapter

class RecipeAdapter(val context: Context, var recipes: MutableList<Recipe>) : RecyclerView.Adapter<RecipeAdapter.ViewHolder>() {

override fun getItemCount(): Int = recipes.size


override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {

val view = LayoutInflater.from(context).inflate(R.layout.recipe_rec_row, null)

return ViewHolder(view)


}

override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
holder?.bindViews(recipes[position])
}


inner class ViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {

fun bindViews(recipe: Recipe) {

itemView.textView7.text = recipe.title
itemView.textView9.text = recipe.ingredients
itemView.button6.setOnClickListener() {

if(!recipe.link.trim().isEmpty())
context.startActivity<ShowLinkAct>("url" to recipe.link)
else
context.toast("No link available")

}

if (!recipe.thumbnail.isEmpty()) {

Picasso.with(context)
.load(recipe.thumbnail)
.placeholder(android.R.drawable.ic_menu_report_image)
.error(android.R.drawable.ic_menu_report_image)
.into(itemView.imageView)

} else {
Picasso.with(context).load(android.R.drawable.ic_menu_report_image).into(itemView.imageView)
}


}

}
}

我期待着您的建议,在此先感谢您

最佳答案

我建议您将适配器的数据存储在适配器内部。如果您使用的是 AAC,您还应该检查 GithubBrowser 的示例。这是一个小的(未经测试的)样本。

警告:您不应在 RecyclerView 中使用上下文操作,因为您可能会泄漏。

BaseAdapter(所有适配器都扩展了这个具有 DiffUtil 的适配器)

abstract class DataBoundListAdapter<T, V : ViewDataBinding> : RecyclerView.Adapter<DataBoundViewHolder<V>>() {

val log = AnkoLogger(javaClass.simpleName)

private var items: List<T>? = null

private var dataVersion = 0

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBoundViewHolder<V> {
val binding = createBinding(parent)
return DataBoundViewHolder(binding)
}

protected abstract fun createBinding(parent: ViewGroup): V

override fun onBindViewHolder(holder: DataBoundViewHolder<V>, position: Int) {
bind(holder.binding, items!![position])
holder.binding.executePendingBindings()
}


@SuppressLint("StaticFieldLeak")
@MainThread
fun replace(update: List<T>?) {
dataVersion++
if (items == null) {
if (update == null) {
return
}
items = update
notifyDataSetChanged()
} else if (update == null) {
val oldSize = items!!.size
items = null
notifyItemRangeRemoved(0, oldSize)
} else {
val startVersion = dataVersion
val oldItems = items
object : AsyncTask<Void, Void, DiffUtil.DiffResult>() {
override fun doInBackground(vararg voids: Void): DiffUtil.DiffResult {
return DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldItems!!.size
}

override fun getNewListSize(): Int {
return update.size
}

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldItems!![oldItemPosition]
val newItem = update[newItemPosition]
return this@DataBoundListAdapter.areItemsTheSame(oldItem, newItem)
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldItems!![oldItemPosition]
val newItem = update[newItemPosition]
return this@DataBoundListAdapter.areContentsTheSame(oldItem, newItem)
}
})
}

override fun onPostExecute(diffResult: DiffUtil.DiffResult) {
if (startVersion != dataVersion) {
// ignore update
return
}
items = update
diffResult.dispatchUpdatesTo(this@DataBoundListAdapter)

}
}.execute()
}
}

protected abstract fun bind(binding: V, item: T)

protected abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean

protected abstract fun areContentsTheSame(oldItem: T, newItem: T): Boolean

override fun getItemCount(): Int {
return if (items == null) 0 else items!!.size
}


}

这是一个示例适配器。如果您使用 AAC,您可能需要使用数据绑定(bind)。我建议你这样做!注意上下文操作不应该在 RecyclerView 中,因为你可能会泄漏。

class RecipeAdapter(private val dataBindingComponent: DataBindingComponent,
private val yourVm: ViewModel, private val context: Context) : DataBoundListAdapter<Recipe, RecipeRecRowBinding>() {


override fun createBinding(parent: ViewGroup): RecipeRecRowBinding {
val binding = DataBindingUtil.inflate<RecipeRecRowBinding>(LayoutInflater.from(parent.context), R.layout.recipe_rec_row, parent, false, dataBindingComponent)
return binding
}

override fun bind(binding: RecipeRecRowBinding, recipe: Recipe) {
binding.model = recipe
binding.viewModel = yourVm


binding.itemView.textView7.text = recipe.title
binding.itemView.textView9.text = recipe.ingredients
binding.itemView.button6.setOnClickListener() {

if(!recipe.link.trim().isEmpty())
//ohoh, you shouldnt call something on your activity within your adapter
context.startActivity<ShowLinkAct>("url" to recipe.link)
else
//ohoh, you shouldnt call something on your activity within your adapter
context.toast("No link available")

}

if (!recipe.thumbnail.isEmpty()) {

Picasso.with(context)
.load(recipe.thumbnail)
.placeholder(android.R.drawable.ic_menu_report_image)
.error(android.R.drawable.ic_menu_report_image)
.into(itemView.imageView)

} else {
Picasso.with(context).load(android.R.drawable.ic_menu_report_image).into(itemView.imageView)
}

}


override fun areItemsTheSame(oldItem: Recipe, newItem: Recipe) = oldItem.id == newItem.id


override fun areContentsTheSame(oldItem: Recipe, newItem: Recipe) = oldItem.equals(newItem)


}

最后是您的订阅者,它将数据推送到您的适配器并注意更改 (DiffUtil)

fun subscribe() {
val observer = Observer<Recipe> {

if (it!= null) {
// it cant be null since you validate it here
Log.d("mike", "subscribe ${it.title} ")
adapter.replace(it)

}
}

viewModel?.mRecipe?.observe(this, observer)
}

关于android - 我的 RecyclerView 没有得到适当的通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46426352/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com