gpt4 book ai didi

android - WindowManager 内的 RecyclerView 不更新

转载 作者:行者123 更新时间:2023-12-05 00:17:47 35 4
gpt4 key购买 nike

我尝试在我的应用程序中创建一个通知覆盖层,它可以显示有关某些应用程序明智的重要事件的通知。
我决定使用 RecyclerView将直接淹没在WindowManager .
这适用于显示初始项目,但是项目不会更新。
下面是我的实现。所以当我调用 start not1not2显示,但当 removeNotification函数被调用,通知实际上已被删除,并且正在向适配器提交正确的列表,但屏幕上的 View 不会更新。
但是,如果我添加 windowManager.updateViewLayout(recyclerView, layoutParams)submitList 之后里面 removeNotification ,一切似乎都按预期工作,但这次我失去了 RV 动画..
由于这是我第一次直接使用 WindowManager,我很困惑。如果可能的话,有人可以帮我弄清楚发生了什么以及如何实现我想要的。

class NotificationOverlay(private val context: Context) {

private val windowManager: WindowManager =
context.getSystemService(Context.WINDOW_SERVICE) as WindowManager

private val layoutParams = WindowManager.LayoutParams().apply {
gravity = android.view.Gravity.TOP or android.view.Gravity.CENTER_HORIZONTAL
width = WindowManager.LayoutParams.MATCH_PARENT
height = WindowManager.LayoutParams.WRAP_CONTENT
format = PixelFormat.TRANSLUCENT
dimAmount = 0.5f
flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND
type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL
}

private val notifications = mutableListOf<NotificationItem>().also {
it.addAll(listOf(
NotificationItem(title = "not 1", message = "first notification"),
NotificationItem(title = "not 2", message = "second notification")
))
}
private val notificationsAdapter = NotificationAdapter(::removeNotification)
private val recyclerView = RecyclerView(context).apply {
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
adapter = notificationsAdapter
}


private fun removeNotification(notification: NotificationItem){
notifications.remove(notification)
notificationsAdapter.submitList(notifications)
if(notificationsAdapter.currentList.isEmpty()){
windowManager.removeView(recyclerView)
}
}

fun show(){
windowManager.addView(recyclerView, layoutParams)

notificationsAdapter.submitList(notifications)
}
}
已编辑
好吧,我发现问题不在于WindowManager,而在于DiffUtils,但无法理解它有什么问题,因为它非常简单,我多次实现了这样的DiffUtils,无论如何,我会发布代码如果您对为什么这不起作用有任何想法,请在这里:
    class NotificationAdapter(private val onCloseClicked: (NotificationItem) -> Unit):
ListAdapter<NotificationItem, NotificationAdapter.NotificationViewHolder>(DiffCallback()) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationViewHolder {
val binding = ItemNotificationOverlayBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return NotificationViewHolder(binding, onCloseClicked)
}


override fun onBindViewHolder(holder: NotificationViewHolder, position: Int) {
holder.bind(currentList[position])
}

class NotificationViewHolder(private val itemBinding: ItemNotificationOverlayBinding, private val onCloseClicked: (NotificationItem) -> Unit): RecyclerView.ViewHolder(itemBinding.root) {
fun bind(item: NotificationItem) {
itemBinding.title.text = item.title
itemBinding.message.text = item.message
itemBinding.close.setOnClickListener {
onCloseClicked.invoke(item)
}
}
}

class DiffCallback : DiffUtil.ItemCallback<NotificationItem>() {

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

override fun areContentsTheSame(oldItem: NotificationItem, newItem: NotificationItem) =
oldItem == newItem
}
}
在这样一个简单的结构中,每个人都有什么问题?我已经快疯了,想扔掉这个 DiffUtils 并实现老派 notifyItemRemoved 已编辑 2
所以@IamFr0ssT 提供的答案解决了这个问题。我更深入地了解为什么会发生这种情况,原因在 androidx.recyclerview.widget.AsyncListDiffer主类 submitList功能。它在那里进行以下检查:
if (newList == mList) {
// nothing to do (Note - still had to inc generation, since may have ongoing work)
if (commitCallback != null) {
commitCallback.run();
}
return;
}
因此,当我提交列表的相同引用时,甚至从未尝试计算我的差异。
什么额外的 toList() @IamFr0ssT 建议的函数确实创建了列表的一个新实例,从而使计算我的差异的差异。如果你深入了解 toList()函数,它最终会创建一个 ArrayList 的新实例基于提供的列表 ...return ArrayList(this)好吧,这个问题与 WindowManager 无关只是 DiffUtil

最佳答案

您正在传递 MutableList notifications到适配器,并且适配器没有制作列表的副本,它只是使用相同的列表。
当您在 removeNotification 中编辑列表时回调,您正在编辑适配器正在使用的列表。
因此,当计算差异时,它会将它认为当前显示但未显示的列表与其自身进行比较。因此没有差异,也没有 notifyItemRemoved或其他事件。
我想你可以做些什么来修复它,只需调用 .toList()调用 submitList() 时在可变列表中:

class NotificationOverlay(private val context: Context) {
...

private fun removeNotification(notification: NotificationItem){
notifications.remove(notification)
notificationsAdapter.submitList(notifications.toList())
if(notificationsAdapter.currentList.isEmpty()){
windowManager.removeView(recyclerView)
}
}

fun show(){
windowManager.addView(recyclerView, layoutParams)

notificationsAdapter.submitList(notifications.toList())
}
}
另外,您如何获得 NotificationItem.id?每个条目应该不同。

关于android - WindowManager 内的 RecyclerView 不更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72688566/

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