Android ViewModel 在观察时删除了我的所有数据。

huangapple go评论78阅读模式
英文:

Android ViewModel deletes all my data when observing

问题

我正在使用Android Studio开发应用程序,并希望在RecyclerView中使用MutableLiveData。问题是,当我向MutableLiveData添加新项时,它会得到更新,然后返回到先前的片段时,项目会出现未知原因被清除。

FirstFragment.javaonCreateView 方法的代码部分:

@Override
public View onCreateView(
        LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState
) {
    binding = FragmentFirstBinding.inflate(inflater, container, false);

    notificationsViewModel = new ViewModelProvider(requireActivity()).get(NotificationsViewModel.class);

    // 绑定RecyclerView
    RecyclerView rvNotification = binding.registeredNotification;
    Log.d("NA", "New Adapter");
    NotificationAdapter adapter = new NotificationAdapter();
    Log.d("NA", "Setting adapter");
    rvNotification.setAdapter(adapter);
    Log.d("NA", "Setting layout");
    rvNotification.setLayoutManager(new LinearLayoutManager(getActivity()));
    Log.d("NA", "Getting the MLD");
    MutableLiveData<List<NotificationContent>> notifs = notificationsViewModel.getNotifications();
    Log.d("NA", "Adding observer");
    notifs.observe(requireActivity(), new Observer<List<NotificationContent>>() {
        @Override
        public void onChanged(List<NotificationContent> notificationContents) {
            Log.d("ANDROIDAPP", String.format("onChanged: detected and done, item size %d", notificationContents.size()));
            adapter.updateNotifications(notificationContents);
        }
    });

    return binding.getRoot();
}

ViewModel 实现的代码部分:

public class NotificationsViewModel extends ViewModel {
    private final MutableLiveData<List<NotificationContent>> notifications = new MutableLiveData<List<NotificationContent>>();

    public MutableLiveData<List<NotificationContent>> getNotifications() {
        if (notifications.getValue() == null) {
            notifications.setValue(new ArrayList<NotificationContent>());
        }
        return notifications;
    }

    public void removeNotification(NotificationContent notificationContent) {
        List<NotificationContent> n = getNotifications().getValue();
        n.remove(notificationContent);
        notifications.setValue(n);
    }

    public void addNotification(NotificationContent notificationContent) {
        List<NotificationContent> n = getNotifications().getValue();
        n.add(notificationContent);
        notifications.setValue(n);
    }

    public void addNotification(int position, NotificationContent notificationContent) {
        List<NotificationContent> n = getNotifications().getValue();
        n.add(position, notificationContent);
        notifications.setValue(n);
    }
}

最后是 RecyclerView.Adapter 的代码:

public class NotificationAdapter extends RecyclerView.Adapter<NotificationAdapter.ViewHolder> {
    public class ViewHolder extends RecyclerView.ViewHolder {
        // 视图项声明...
        public ViewHolder(View itemView) {
            super(itemView);
            // 检索视图项...
        }
    }

    private List<NotificationContent> mNotifications = new ArrayList<>();

    public void updateNotifications(List<NotificationContent> newNotifications) {
        Log.d("NA", "Clearing");
        this.mNotifications.clear();
        Log.d("NA", "Setting");
        this.mNotifications = newNotifications;
        Log.d("NA", "NotifyChangedDataset");
        this.notifyDataSetChanged();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // 一些代码...
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        // 一些代码...
    }

    @Override
    public int getItemCount() {
        return mNotifications.size();
    }
}

从你提供的代码和日志来看,似乎问题出现在 onChanged 方法中,当数据更改时,你清空了 mNotifications 并重新设置它,然后调用 notifyDataSetChanged,这可能导致数据在返回到先前的片段时丢失。你可以尝试不清空 mNotifications,而是直接将新的通知列表分配给它,然后调用 notifyDataSetChanged。这样应该能够保留数据。

英文:

I am developing an app with Android Studio, and I wish to use MutableLiveData alongside with RecyclerView. Problem is, when I add a new item to the MutableLiveData, it gets updated, then going back to the previous fragment, the item gets erased for some unknown reason.
Code in my FirstFragment.java for the method onCreateView:

@Override
    public View onCreateView(
            LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {
        binding = FragmentFirstBinding.inflate(inflater, container, false);

        notificationsViewModel = new ViewModelProvider(requireActivity()).get(NotificationsViewModel.class);

        // Binding recycler views
        // Notifications

        RecyclerView rvNotification = binding.registeredNotification;

        Log.d(&quot;NA&quot;, &quot;New Adapter&quot;);
        NotificationAdapter adapter = new NotificationAdapter();

        Log.d(&quot;NA&quot;, &quot;Setting adapter&quot;);
        rvNotification.setAdapter(adapter);

        Log.d(&quot;NA&quot;, &quot;Setting layout&quot;);
        rvNotification.setLayoutManager(new LinearLayoutManager(getActivity()));

        Log.d(&quot;NA&quot;, &quot;Getting the MLD&quot;);
        MutableLiveData&lt;List&lt;NotificationContent&gt;&gt; notifs = notificationsViewModel.getNotifications();

        Log.d(&quot;NA&quot;, &quot;Adding observer&quot;);
        notifs.observe(requireActivity(), new Observer&lt;List&lt;NotificationContent&gt;&gt;() {
            @Override
            public void onChanged(List&lt;NotificationContent&gt; notificationContents) {
                Log.d(&quot;ANDROIDAPP&quot;, String.format(&quot;onChanged: detected and done, item size %d&quot;, notificationContents.size()));
                adapter.updateNotifications(notificationContents);
            }
        });

        return binding.getRoot();
    }

Code of the ViewModel implementation :

public class NotificationsViewModel  extends ViewModel {
    private final MutableLiveData&lt;List&lt;NotificationContent&gt;&gt; notifications = new MutableLiveData&lt;List&lt;NotificationContent&gt;&gt;();

    public MutableLiveData&lt;List&lt;NotificationContent&gt;&gt; getNotifications() {
        if (notifications.getValue() == null) {
            notifications.setValue(new ArrayList&lt;NotificationContent&gt;());
        }
        return notifications;
    }

    public void removeNotification(NotificationContent notificationContent) {
        List&lt;NotificationContent&gt; n = getNotifications().getValue();
        n.remove(notificationContent);
        notifications.setValue(n);
    }

    public void addNotification(NotificationContent notificationContent) {
        List&lt;NotificationContent&gt; n = getNotifications().getValue();
        n.add(notificationContent);
        notifications.setValue(n);
    }

    public void addNotification(int position, NotificationContent notificationContent) {
        List&lt;NotificationContent&gt; n = getNotifications().getValue();
        n.add(position, notificationContent);
        notifications.setValue(n);
    }
}

And finally code of the RecyclerView.Adapter :

public class NotificationAdapter extends RecyclerView.Adapter&lt;NotificationAdapter.ViewHolder&gt; {

    public class ViewHolder extends RecyclerView.ViewHolder {

        // View Items declaration...

        public ViewHolder(View itemView) {
            super(itemView);
            // View items retrieval ...
        }
    }

    private List&lt;NotificationContent&gt; mNotifications = new ArrayList&lt;&gt;();

    public void updateNotifications(List&lt;NotificationContent&gt; newNotifications) {
        Log.d(&quot;NA&quot;, &quot;Clearing&quot;);
        this.mNotifications.clear();

        Log.d(&quot;NA&quot;, &quot;Setting&quot;);
        this.mNotifications = newNotifications;

        Log.d(&quot;NA&quot;, &quot;NotifyChangedDataset&quot;);
        this.notifyDataSetChanged();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // Some code ...
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        // Some code ...     
    }

    @Override
    public int getItemCount() {
        return mNotifications.size();
    }
}

To get an idea of the interplay between my fragments here is my nav_graph.xml graphical representation :
Android ViewModel 在观察时删除了我的所有数据。

But the problem is that after adding an item through the addNotificationFragment it ends up emptying, here is the log from the log given in the code :

D/ANDROIDAPP: onViewCreated: addNotification 1
D/ANDROIDAPP: onChanged: detected and done, item size 1
D/NA: Clearing
D/NA: Setting
D/NA: NotifyChangedDataset
D/ANDROIDAPP: onViewCreated: addNotification 2
D/ForceDarkHelper: updateByCheckExcludeList: pkg: com.etilawin.tgvmaxplanner activity: com.etilawin.tgvmaxplanner.MainActivity@df816d4
D/ForceDarkHelper: updateByCheckExcludeList: pkg: com.etilawin.tgvmaxplanner activity: com.etilawin.tgvmaxplanner.MainActivity@df816d4
D/NA: New Adapter
D/NA: Setting adapter
D/NA: Setting layout
D/NA: Item Touche helper
D/NA: Button listener
D/NA: Getting the MLD
D/NA: Adding observer
D/ANDROIDAPP: onChanged: detected and done, item size 0
D/NA: Clearing
D/NA: Setting
D/NA: NotifyChangedDataset

答案1

得分: 0

我不确定为什么但解决方案在这一行中
```java
 notifs.observe(requireActivity(), new Observer&lt;List&lt;NotificationContent&gt;&gt;() {
            ...
        });

这里的 requireActivity() 是不正确的,应该改成 getViewLifecycleOwner()


<details>
<summary>英文:</summary>
I don&#39;t know exactly why but the solution resides in this line :
```java
notifs.observe(requireActivity(), new Observer&lt;List&lt;NotificationContent&gt;&gt;() {
...
});

Here requireActivity() is not correct it should be getViewLifecycleOwner().

huangapple
  • 本文由 发表于 2023年2月18日 21:51:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/75493784.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定