RecyclerView не обновляет свое представление, но список обновляется - PullRequest
0 голосов
/ 06 августа 2020

Я использую recyclerView, чтобы показать список доступных приложений на устройстве ... более того, я использую bottomSheet, чтобы показать более подробную информацию о выбранном приложении ... в этом разделе я помещаю кнопку удаления ... здесь я использую код удаления и из метод onActivityResult в файле BottomSheetDialog.kt ... при нажатии OK .... Я хочу удалить это приложение / элемент из списка и обновить View .... здесь список верен в коде, но recyclerView не t обновить свой список

Примечание: я отлаживал код и обнаружил, что список обновлен в файле BottomSheet ... Я комментирую это .... но recyclerView не

Я искал по inte rnet, но не нашел решения, подходящего для моего случая

MainActivity.kt

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
   
    
    recyclerView.adapter = Adapter(applicationList) // here I send mutable list of all apps in device to adapter
    recyclerView.layoutManager = LinearLayoutManager(this)


private fun getApps(List: MutableList<ResolveInfo>): MutableList<AppData> {
     // here I return list to adapter with details of installed apps like icon, name, packageName etc
    }

DataClass

data class AppData(
val icon: Drawable,
val name: String,
val packageName: String
.....
.....)

Adapter.kt

class Adapter(private val listOfApps: MutableList<AppData>) :
RecyclerView.Adapter<Adapter.ViewHolder>() {
 // here I receive mutableList in constructor of Adapter

class ViewHolder(appView: View) : RecyclerView.ViewHolder(appView), View.OnClickListener,
    View.OnLongClickListener {

    init { // initiate both click listeners
        appView.setOnClickListener(this)
        appView.setOnLongClickListener(this)
    }
    // call elements from activity.xml
    val icon: ImageView = appView.App_icon
    val name: TextView = appView.App_name
    val size: TextView = appView.App_size

    override fun onClick(v: View?) {
        Toast.makeText(v?.context, "OnClick", Toast.LENGTH_SHORT).show()

    }

    override fun onLongClick(v: View?): Boolean {
        val bottomSheetDialog = BottomSheetDialog(currentItem, appList) 
        // send currentItem and all List to BottomSheetDialog to show details with the help of function 
       
        // Show bottomSheet on LongPress
        return true
    }

    
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder // done

override fun getItemCount() = listOfApps.size

override fun onBindViewHolder(holder: ViewHolder, position: Int) {

    val currentItem = listOfApps[position]
    holder.icon.setImageDrawable(currentItem.icon) 
    holder.name.text = currentItem.name
    holder.size.text = currentItem.size
  }

BottomSheetDialog.kt ...... здесь, в onActivtyResult, я удаляю элемент и вызываю метод уведомления ... проблема здесь

class BottomSheetDialog(private val appData: AppData, private val appList: MutableList<AppData>) :
BottomSheetDialogFragment() {
 // here I receive appData and AppList in constructor from Adapter OnLongPress

override fun onCreateView() // done
    
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      
   // here when bottomSheet popup and on click of uninstall.....I check whether user click on OK or CANCEL in onActivity Method (overidden below)
   
     Uninstall_App.setOnClickListener {
        // permission in manifest added
        val intent = Intent(Intent.ACTION_DELETE)
        intent.data = Uri.parse("package:${appData.packageName}")
        intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
        startActivityForResult(intent, 1)
    }

    
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    // get result from uninstall dialog
    if (resultCode == -1) { // ok pressed
        Toast.makeText(context, "ok clicked", Toast.LENGTH_SHORT).show()
        dismiss()

       // here when user pressed OK....delete that item from List
        val index = appList.indexOf(appData)
        appList.removeAt(index)
        Adapter(appList).notifyItemRemoved(index)
        Adapter(appList).notifyDataSetChanged()
        
        // I check above three line by debugging it 
        // 1. val index .. return index of current item
        // 2. this line remove that item
        // 3. Adapter(appList) .... notify Item removed 
        // 4. here that indexed item is removed but view is not updated
        // Note: if it is wrong which is the best method to do this 

    } else if (resultCode == 0) { // cancel pressed
        Toast.makeText(context, "Cancel Click", Toast.LENGTH_SHORT).show()
    }
}

Ответы [ 3 ]

0 голосов
/ 06 августа 2020

То, что вы здесь сделали, создано два новых адаптера (которые не имеют никакого отношения к адаптеру, используемому представлением recycler, за исключением того, что тип адаптера тот же):

Adapter(appList).notifyItemRemoved(index)
Adapter(appList).notifyDataSetChanged()

You можно создать интерфейс для прослушивания изменений из BottomSheetDialog:

interface OnAppDeletedListener {
    fun appDeletedAtIndex(index: Int)
}

Обновите свой BottomSheetDialog, чтобы принять дополнительный аргумент типа OnAppDeletedListener:

class BottomSheetDialog(private val appData: AppData, private val appList: MutableList<AppData>, private val listener: OnAppDeletedListener) :
    BottomSheetDialogFragment() {
    
    ...
        
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) {
            val index = appList.indexOf(appData)
            listener.appDeletedAtIndex(index)  
            dismiss() 
        }
    }
}

Обновите свой адаптер . Он не должен отвечать за отображение каких-либо диалогов . За это отвечает действие или фрагмент.

class Adapter(private val listOfApps: MutableList<AppData>, private val longClickListener: View.OnLongClickListener) :
    RecyclerView.Adapter<Adapter.ViewHolder>() {
     // here I receive mutableList in constructor of Adapter

    class ViewHolder(appView: View) : RecyclerView.ViewHolder(appView), View.OnClickListener {

        init { // initiate both click listeners
            appView.setOnClickListener(this)
            appView.setOnLongClickListener(longClickListener)
        }
        // call elements from activity.xml
        val icon: ImageView = appView.App_icon
        val name: TextView = appView.App_name
        val size: TextView = appView.App_size

        override fun onClick(v: View?) {
            Toast.makeText(v?.context, "OnClick", Toast.LENGTH_SHORT).show()
        }
     }
}

И обновите свой код активности:

 class MainActivity : AppCompatActivity() {

    private lateinit var adapter: Adapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
       
        val longClickListener = object: View.OnLongClickListener {
                override fun onLongClick(v: View?): Boolean {
                    displayAppInfoDialog()
                    return true
                }
            }
        adapter = Adapter(applicationList)
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)
    }

    private fun displayAppInfoDialog() {
        val listener = object: OnAppDeletedListener() {
                fun appDeletedAtIndex(index: Int) {
                    adapter.notifyItemRemoved(index)
                }
            }
        val bottomSheetDialog = BottomSheetDialog(currentItem, appList, listener)
        bottomSheetDialog.show()
    }

    ...
}
0 голосов
/ 06 августа 2020

Как уже было сказано, вы не обновляете существующий адаптер, вместо этого вы создаете два новых экземпляра.

Замените эту строку:

recyclerView.adapter = Adapter(applicationList) // here I send mutable list of all apps in device to adapter

на

this.adapter = Adapter(applicationList)
recyclerView.adapter = this.adapter

Также добавьте val adapter: Adapter? в свой класс.

Теперь у вас есть ссылка на адаптер, который есть в RecyclerView.

Наконец, когда вы захотите «обновить» его:


       // here when user pressed OK....delete that item from List
        val index = appList.indexOf(appData)
        appList.removeAt(index)
        Adapter(appList).notifyItemRemoved(index)
        Adapter(appList).notifyDataSetChanged()
        

Должно стать ...


       // here when user pressed OK....delete that item from List
        val index = appList.indexOf(appData)
        appList.removeAt(index)
        
        this.adapter.notifyItemRemoved(index)
        this.adapter.notifyDataSetChanged()

ВАЖНАЯ ПРОБЛЕМА : здесь есть и другие проблемы с разделением проблем в вашем коде, но среди них тот факт, что appList, который вы здесь используете, является локальным списком; содержит ли он элементы из applicationList (тот, который вы использовали при создании адаптера )? Если это не так, вам нужно открыть указанный список, чтобы вы могли либо изменить его / заменить, и т. Д. c.

Адаптер НЕ управляет списком за вас, он просто использует его для адаптации каждого элемента к ViewHolder. Если вы изменяете список, который есть у адаптера, и сообщаете ему, что вставили элемент в определенную позицию, et c. Все, что делает адаптер, - это (много за кулисами) и «повторно привязывает» вид в этой позиции (если он виден) с новыми данными.

0 голосов
/ 06 августа 2020

эти строки

Adapter(appList).notifyItemRemoved(index)
Adapter(appList).notifyDataSetChanged()

создают новые адаптеры, уведомляют их и .. вот и все. они не прикреплены ни к какому RecyclerView (как в onCreate), поэтому нигде не будут нарисованы

вы должны уведомить адаптер, уже установленный для RecyclerView - сохраните ссылку в Activity и обратитесь к нему вместо создания нового

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...