Search code examples
javaandroidandroid-recyclerviewandroid-livedatamutablelivedata

Android ViewModel deletes all my data when observing


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("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();
    }

Code of the ViewModel implementation :

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);
    }
}

And finally code of the RecyclerView.Adapter :

public class NotificationAdapter extends RecyclerView.Adapter<NotificationAdapter.ViewHolder> {

    public class ViewHolder extends RecyclerView.ViewHolder {

        // View Items declaration...

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

    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) {
        // 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 : nav graph in Android Studio capture

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

Solution

  • I don't know exactly why but the solution resides in this line :

     notifs.observe(requireActivity(), new Observer<List<NotificationContent>>() {
                ...
            });
    

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