【问题标题】:notifyDataSetChanged() fails to update correctly due to ArrayList to Adapter binding issues由于 ArrayList 到适配器的绑定问题,notifyDataSetChanged() 无法正确更新
【发布时间】:2019-06-13 05:25:25
【问题描述】:

我已阅读以下内容:

ArrayList not updating after using .clear()
notifydataSetChanged working but only showing 1 result in listview Android
notifyDataSetChanged() does not affect my adapterView
Android: notifyDataSetChanged(); not working
notifydatasetchanged() not working after onbackpressed()
Android notifyDataSetChanged not working
Android notifyDataSetChanged() not working

仍然无法让我的适配器从新数据集进行更新。

我在调试模式的代码如下:

public class PetInformationActivity extends AppCompatActivity
implements ConfirmDialogFragment.ConfirmDialogListener, MedicalInformationFragment.OnFragmentInteractionListener{

private static List<Assignment> listAssignments = new ArrayList<>();
private static AssignmentsAdapter mAdapter;
private static PetInformationViewModel sPetInformationViewModel;
.
.
.
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
.
.
.
/**
* get the providers' IDs assigned to the pet: fillAssignmentsArray()
*/
listAssignments = sPetInformationViewModel.getAssignedProviders(petId);

此时调试中:
mAdapter = null
listAssignments = (ArrayList@5411) size = 0

Log.d(TAG, "listAssignments has " + listAssignments.size() + " Assignment objects in it");  
Log.d(TAG, "listAssignments is: " + listAssignments);   

此时调试中:
mAdapter = null
listAssignments = (ArrayList@5461) size = 1
0 = (Assignment@5496)"Assignment{mType='兽医', mProviderName='red 兽医'}"

mAdapter = new AssignmentsAdapter(this, listAssignments);   

此时调试中:
mAdapter = (AssignmentsAdapter@5499)
listAssignments = (ArrayList@5461) size = 1
0 = (Assignment@5496)"Assignment{mType='Veterinarian', mProviderName='red vet'}"

mRecyclerView.setAdapter(mAdapter);
.
.
.
}

public void onResume(){
super.onResume();
Log.d(TAG, "Entered: onResume");
listAssignments.clear();
Log.d(TAG, "listAssignments is: " + listAssignments);

此时调试中:
mAdapter = (AssignmentsAdapter@5499)
listAssignments = (ArrayList@5461) size = 0**

listAssignments = sPetInformationViewModel.getAssignedProviders(petId);
Log.d(TAG, "listAssignments is: " + listAssignments);

此时调试中:
mAdapter = (AssignmentsAdapter@5499)
listAssignments = (ArrayList@5594) size = 1
0 = (Assignment@5607)"Assignment{mType='Veterinarian', mProviderName='red vet'}"

mAdapter.notifyDataSetChanged();
}  

此时屏幕是空白的,它应该显示在 Assignment@5607 中显示的文本。似乎 notififyDataSetChanged() 通知 mAdapter 从 onCreate (ArrayList@5461) 中显示的文本更改为在 onResume (ArrayList@5461) 中清除,而不是在 onResume (ArrayList@5594) 中对数据的新调用。

这似乎表明当 mAdapter 被初始化为 listAssignments 时,它被设置为使用地址 @5461 的 ArrayList。当在 onResume 中调用新数据时,在 a) 使用后退按钮返回和 (b) 当此 Activity 首次启动时,在不同的地址创建一个新的 ArrayList。

因此,我似乎没有正确合并我的 ArrayList,因为对 listAssignments 的所有更新都将导致一个全新的 ArrayList 对象,该对象从未用于更新 mAdapter,该对象将始终更新为地址 @5461 处的初始 ArrayList。

我已经搜索了有关如何正确地将适配器绑定到 ArrayList 的信息,但我没有找到任何比我所做的更多的暗示。我假设 notifyDataSetChanged() 的目的是使用现有的适配器进行更新,这样现有的适配器就不必被销毁,并且在每个数据集更改时创建一个新的适配器,如下所示:

notifyDataSetChanged() fails to update adapter onClick

【问题讨论】:

    标签: java android arraylist notifydatasetchanged


    【解决方案1】:

    您传递给 ArrayAdapter 的引用与此处分配的不同:

    listAssignments = sPetInformationViewModel.getAssignedProviders(petId);
    

    就 ArrayAdapter 而言,它所引用的 listAssignments 已被清除 OnResume 并且没有任何内容被添加回它。它对新的 listAssignments 引用一无所知。

    尝试这样做:

    public void onResume()
    {
        super.onResume();
        Log.d(TAG, "Entered: onResume");
        listAssignments.clear();
        Log.d(TAG, "listAssignments is: " + listAssignments);
        List<Assignment> newList = sPetInformationViewModel.getAssignedProviders(petId);
        listAssignments.addAll(newList);
        mAdapter.notifyDataSetChanged();
    }
    

    【讨论】:

    • 好的。这有助于在 Activity 启动时显示正确的值。但是, onResume 中的 notifyDataSetChanged() (如您所建议的)应该在从另一个 Activity 返回时重新显示一个新值。由于这个新值是从 SQLite DB 获得的,因此没有从该 Activity 传递的值,该值是在 onResume 中获得的,如您的建议所示。但是,它不起作用,显示旧值并且新的ArrayList地址是新的,而不是@5461。因此,适配器永远不会更新!我是否需要每次都更换一个新的适配器?其他帖子说不。
    • @Jeff - 当您从另一个活动返回时,您是否验证过您的 ViewModel 在 OnResume 中返回的项目不同?值得一提的是,如果您想在从另一个活动返回时刷新列表,最好使用startActivityForResultonActivityResult,因为OnResume 可用于许多其他场景,包括启动活动、设备旋转等。请参阅这个答案:stackoverflow.com/a/37227482/2754727
    • 是的,ArrayList 的地址在 Activity 启动时为 5461,在被调用 Activity 使用 onBackPressed() 返回时为 5767。我将研究这些方法,但是被调用的 Activity 只是将一个值存储在一个 DB 表中,然后如您的 onResume() 所示进行访问,没有值传递回调用 Activity。除了 List 之外,是否还有其他东西可以在调用 Activity (PetInformationActivity) 的整个生命周期中使用相同的基地址,或者有没有办法将其基地址设置为永不改变?
    • 我通过添加: mAdapter = new AssignmentsAdapter(this, listAssignments); mRecyclerView.setAdapter(mAdapter);您的 onResume 建议。但是,这种解决方法可能效率非常低,并且无法解决 notifyDataSetChanged() 不起作用的事实,因为每次调用时 ArrayList 地址都会更改,因此永远不会使用最新的数据集来更新显示。
    • @Jeff - 您可能想尝试在您的 AssignmentsAdapter 中公开一个方法来修改它在内部保存的列表引用。这可能无需初始化新适配器即可工作
    【解决方案2】:

    好吧,我在这里说一下 notifyDataSetChanged() 对 ArrayList 不起作用,因为在每次加载时它的地址都会发生变化,请参阅我的原始帖子和 cmets 到 pnavk 以查看详细信息。据我了解,Java 无法像 C 或 C++ 那样通过指针固定 ArrayList 的地址,因此适配器被设置为原始 ArrayList 对象的内存位置,因此每次都指向相同的数据即使 Java 为该 ArrayList 对象使用了新的内存位置,或者创建了一个全新的同名 ArrayList 对象,也会调用 notifyDataSetChanged()。

    因此,我从 ArrayList 中的新数据集更新 RecyclerView 的答案是将 onResume 中的 Adapter 重置为新的,然后将该 Adapter 重新分配给您的 RecyclerView,正如我在对 pnavk 的回复中提到的那样:

    mAdapter = new AssignmentsAdapter(this, listAssignments); 
    mRecyclerView.setAdapter(mAdapter);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-23
      • 1970-01-01
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 2017-06-06
      相关资源
      最近更新 更多