从不同的LiveData来源填充适配器 [英] Filling an adapter from different LiveData sources

查看:69
本文介绍了从不同的LiveData来源填充适配器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在玩LiveData,想了解它可以做什么. 我想通过开关(如果需要,可以使用过滤器)将来自不同来源的数据填充到RecyclerView中.

I'm playing with LiveData and want to understand what it can do. I want to fill my RecyclerView with data from different sources by switch(using filters if you like).

在适配器内部过滤值不是一种选择. 因此,我决定在视图模型中使用 MediatorLiveData .

Filtering values inside an adapter is not an option. So, I decided to use MediatorLiveData inside my view model.

道:

@Query("SELECT * FROM tasks WHERE completed = 0")
LiveData<List<Task>> getActiveTasksLiveData();

@Query("SELECT * FROM tasks")
LiveData<List<Task>> getAllTasksLiveData();

@Query("SELECT * FROM tasks WHERE completed = 1")
LiveData<List<Task>> getClosedTasksLiveData();

回购:

    public LiveData<List<Task>> getActiveTasks() {
        return mTaskDao.getActiveTasksLiveData();
    }

    public LiveData<List<Task>> getAllTasks() {
        return mTaskDao.getAllTasksLiveData();
    }

    public LiveData<List<Task>> getClosedTasks() {
        return mTaskDao.getClosedTasksLiveData();
    }

ViewModel

ViewModel

public class MainViewModel extends AndroidViewModel {

    private final String TAG = "MainViewModel";

    private final AppDataRepository mData;

    private MediatorLiveData<List<Task>> mMediatorTasks;

    public MainViewModel(@NonNull Application application) {
        super(application);

        mData = AppDataInjector.getDataRepository(application.getApplicationContext());

        mMediatorTasks = new MediatorLiveData<>();
        mMediatorTasks.setValue(null);
    }

    public LiveData<List<Task>> getTasks(){
        return mMediatorTasks;
    }

    public void changeTasksOption(int index){
        mMediatorTasks.removeSource(mData.getAllTasks());
        mMediatorTasks.removeSource(mData.getActiveTasks());
        mMediatorTasks.removeSource(mData.getClosedTasks());
        if (index == R.id.navigation_all){
            Log.i(TAG, "Add source: all");
            mMediatorTasks.addSource(mData.getAllTasks(), new Observer<List<Task>>() {
                @Override
                public void onChanged(List<Task> tasks) {
                    Log.i(TAG, "Add source: all - setValue");
                    mMediatorTasks.setValue(tasks);
                }
            });
        } else if (index == R.id.navigation_closed){
            Log.i(TAG, "Add source closed");
            mMediatorTasks.addSource(mData.getClosedTasks(), new Observer<List<Task>>() {
                @Override
                public void onChanged(List<Task> tasks) {
                    Log.i(TAG, "Add source: closed - setValue");
                    mMediatorTasks.setValue(tasks);
                }
            });
        } else {
            Log.i(TAG, "Add source active");
            mMediatorTasks.addSource(mData.getActiveTasks(), new Observer<List<Task>>() {
                @Override
                public void onChanged(List<Task> tasks) {
                    Log.i(TAG, "Add source: active - setValue");

                    mMediatorTasks.setValue(tasks);
                }
            });
        }
    }
}

片段

    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_main, container, false);

        mNavigationView = view.findViewById(R.id.navigation);
        mFab = view.findViewById(R.id.fabMain);
        mRecyclerView = view.findViewById(R.id.mainRecyclerView);

        tasksAdapterLive = new TasksAdapterLive(mAdapterCallback);
        RecyclerView.LayoutManager manager = new GridLayoutManager(getContext(), 1);
        mRecyclerView.setLayoutManager(manager);
        mRecyclerView.setAdapter(tasksAdapterLive);

        // set up bottom navigation listener
        mNavigationView.setOnNavigationItemSelectedListener(item -> {
            mViewModel.changeTasksOption(item.getItemId());
            return true;
        });

        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mViewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        mViewModel.getTasks().observe(this, tasks -> {
            if (tasks != null) {
                tasksAdapterLive.setTasks(tasks);
                tasksAdapterLive.notifyDataSetChanged();
            }
        });

        mViewModel.changeTasksOption(mNavigationView.getSelectedItemId());
    }

如您所见,我决定在视图模型中使用 MediatorLiveData . 我的主要目标-从片段调用 changeTasksOption()时,在适配器内部更改数据.

As you can see, I've decided to use MediatorLiveData inside my view model. My main goal - change data inside adapter when changeTasksOption() called from fragment.

我使用removeSource(),因为据我了解,它从观察中删除了LiveData源. 但是,就我而言,不是.

I use removeSource(), because how I understand it removes LiveData source from observing. But, in my case it does not.

启动应用程序时,日志为:

When I launch app, logs are:

MainViewModel: Add source active
MainViewModel: Add source: active - setValue

当我尝试切换到其他来源时-日志是

When I try switch to another source - logs are

MainViewModel: Add source: all
MainViewModel: Add source: all - setValue
MainViewModel: Add source: active - setValue
MainViewModel: Add source: all - setValue
MainViewModel: Add source: active - setValue
*** repeats about 100 times

RecyclerView闪烁

RecyclerView is blinking

所以,请问. 我究竟做错了什么? 我是否误解了文档? 实际上,removeSourse()的作用是什么? 因为就我而言,它不会删除源.

So, I kindly ask. What am I doing wrong? Did I misunderstood the documentation? What really removeSourse() does? Because in my case it does not remove sources.

万一我的实现方法错误,您如何建议我这样做?

In case my method implementing this is wrong, how do you suggest I do?

谢谢!

EDTITED:

经过几个小时的试验,我找到了解决方案.是的,这很糟糕(也许不是吗?).但这显然不是通用的,因为我们不使用Romm + LiveData

After experimenting for couple of hours I've found solution. Yeep, this is bad(or maybe not?). But clearly this is not universal, because we do not use Romm + LiveData

创建返回列表"的普通会议室功能

Create normal Room functions that return List

@Query("SELECT * FROM tasks WHERE completed = 0")
List<Task> getActiveTasks();

@Query("SELECT * FROM tasks")
List<Task> getAllTasks();

@Query("SELECT * FROM tasks WHERE completed = 1")
List<Task> getClosedTasks();

在回购中创建MutableLiveData

Created MutableLiveData in repo

private MutableLiveData<List<Task>> mTasksTestActive, mTasksTestAll, mTasksTestClosed;

将这些功能添加到仓库中

Add theese functions to repo

public LiveData<List<Task>> getActiveTasksTest() {
    Executors.newSingleThreadExecutor().execute(() -> {
        List<Task> taskList = mTaskDao.getActiveTasks();
        mTasksTestActive.postValue(taskList);
    });
    return mTasksTestActive;
}

public LiveData<List<Task>> getAllTasksTest() {
    Executors.newSingleThreadExecutor().execute(() -> {
        List<Task> taskList = mTaskDao.getAllTasks();
        mTasksTestAll.postValue(taskList);
    });
    return mTasksTestAll;
}

public LiveData<List<Task>> getClosedTasksTest() {
    Executors.newSingleThreadExecutor().execute(() -> {
        List<Task> taskList = mTaskDao.getClosedTasks();
        mTasksTestClosed.postValue(taskList);
    });
    return mTasksTestClosed;
}

ViewModel更改:

ViewModel changes:

public void changeTasksOption(int index) {
    mMediatorTasks.removeSource(mData.getAllTasksTest());
    mMediatorTasks.removeSource(mData.getActiveTasksTest());
    mMediatorTasks.removeSource(mData.getClosedTasksTest());
    if (index == R.id.navigation_all) {
        Log.i(TAG, "Add source: all");
        mMediatorTasks.addSource(mData.getAllTasksTest(), tasks -> {
            Log.i(TAG, "Add source: all - postValue");
            mMediatorTasks.postValue(tasks);
        });
    } else if (index == R.id.navigation_closed) {
        Log.i(TAG, "Add source closed");
        mMediatorTasks.addSource(mData.getClosedTasksTest(), tasks -> {
            Log.i(TAG, "Add source: closed - postValue");
            mMediatorTasks.postValue(tasks);
        });
    } else {
        Log.i(TAG, "Add source active");
        mMediatorTasks.addSource(mData.getActiveTasksTest(), tasks -> {
            Log.i(TAG, "Add source: active - postValue");

            mMediatorTasks.postValue(tasks);
        });
    }
}

现在,通过切换UI,我得到了结果.没有更多的循环,一切似乎都正常.

And now, by switching UI, I have my result. No more loops and everything seems go ok.

但是还是!这是一个不好的解决方案.房间可能有问题吗?

But still! This is a bad solution. Maybe something is wrong with Room?

推荐答案

public void changeTasksOption(int index){
    mMediatorTasks.removeSource(mData.getAllTasks());
    mMediatorTasks.removeSource(mData.getActiveTasks());
    mMediatorTasks.removeSource(mData.getClosedTasks());

不,这不是应该的!

所选选项应位于LiveData中.然后,您可以针对该LiveData使用Transformations.switchMap {来选择正确的LiveData<List<Task>>.

The selected option should be in a LiveData. Then you can use Transformations.switchMap { against that LiveData to select the correct LiveData<List<Task>>.

private MutableLiveData<Integer> mSelectedIndex = new MutableLiveData<>();

private final LiveData<List<Task>> mMediatorTasks = Transformations.switchMap(mSelectedIndex, (index) -> {
    if (index == R.id.navigation_all) {
        return mData.getAllTasksTest();
    } else if (index == R.id.navigation_closed) {
        return mData.getClosedTasksTest();
    } else {
        return mData.getActiveTasksTest();
    }
});

public void changeTasksOption(int index) {
    mSelectedIndex.setValue(index);
}

public LiveData<List<Task>> getTasks(){
    return mMediatorTasks;
}

此外,您应该使用您的mData.get*()方法再次从DAO返回LiveData<List<Task>>,这是一个更好的解决方案.

Also, you should bring your mData.get*() methods to return LiveData<List<Task>> from the DAO again, that was a better solution.

这篇关于从不同的LiveData来源填充适配器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆