在 MVVM 架构中检查 SELECT 查询结果长度的干净方法是什么? [英] What is the clean way to check a SELECT query result's length in MVVM architecture?

查看:43
本文介绍了在 MVVM 架构中检查 SELECT 查询结果长度的干净方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个应用程序,它将使用 SearchView 让用户进行查询以过滤数据.我正在使用 RoomDB,并尝试遵循 中推荐的 Model-View-ViewModel 架构Android 开发者指南.

I am creating an App that will use a SearchView to let user make queries to filter data. I am using RoomDB, and trying to follow Model-View-ViewModel architecture as recommended in Android Developers' Guidelines.

我有一个实体和一个 DAO(现在我的数据库只有一张表).我在 DAO 中有一个方法,如下所示:

I have one entity and one DAO (for now my DB has only one table). I have a method in the DAO that looks like this:

@Query("SELECT * FROM table WHERE column1 = :search OR column2 = :search")
LiveData<List<TableRow>> filteredSearch(String search);

所以,从 AsyncTask 中,我可以使用 RoomDatabase 的实例,对,并获取用户查询的结果,像这样,对吗?

So, from an AsyncTask I can use the RoomDatabase's instance, right, and obtain the results of an user's query, like this, right?

// Let's assume search already contains user's input
String search;

// DatabaseClient is a singleton that holds MyRoomDatabase instance
// I am using it as Repository for now... bad call?
LiveData<List<TableRow>> user_query = DatabaseClient
                     .getInstance(getApplicationContext())
                     //  my DatabaseClient has this method that
                     // I made to call DAO's query method
                     .getFilteredList(search);

因此,我想根据此用户查询的长度在我的主活动中加载一个或另一个片段(如果结果为 0,则片段 A 否则片段 B).这在某种程度上是商业逻辑吗?我想知道......我应该从 Viemodel 还是从视图(AKA Activity)中读取查询的长度?如您所见,我仍然在为 RoomDB 和 ViewModel 苦苦挣扎.

So, I want to load one fragment or another in my Main Activity depending on this user query's length (if 0 results, fragmentA else fragmentB). This is business logic to some extent? I wonder... should I read the query's length from the Viemodel, or from the View (AKA Activity)? As you can see, I am still struggling with RoomDB and ViewModels at all.

我的计划是在 ViewModel 中创建一个方法,该方法使用与上述类似的代码片段返回带有查询结果的 LiveData>,然后从主要活动:

My plan was making a method in the ViewModel that returns the LiveData<List<TableRow>> with the query results by using a code snippet similar to the one above, and then, from the MainActivity:

search_view.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        //  Should I delegate AsyncTask to the Repository AKA
        // DatabaseClient? Maybe... but please bear with me
        class UserSearchTask extends AsyncTask<Void, Void, List<TableRows>> {
            @Override
            protected List<TableRows> doInBackground(Void... voids) {
                TableRowsViewModel my_viewmodel = new TableRowsViewModel(getApplication());
                LiveData<List<TableRows>> search_results;
                search_results = my_viewmodel.getUserSearch(query);
                // TODO I will care about type mismatches later
                return search_results;
            }

            @Override
            protected void onPostExecute(List<TableRows> found_elements) {
                super.onPostExecute(found_elements);
                // TODO So, I want to check user's search results from here
                if ( found_elements.length > 0) {
                    showFragmentB();
                } else {
                    showFragmentA();
                }
            }
        }
    }

半年多没写代码了,有点生疏了.我忘记了我之前知道的关于 ViewModel、LiveData 和其他东西的概念.我的方法是否破坏了 MVVM 的架构?LiveData在我这种逻辑尝试中起到什么作用?我可以直接从一些 LiveData 的方法中读取 SQL 查询结果的长度,或者我应该从中检索列表来这样做吗?

I have been without coding for more than half year, and I am a little rusty. I forgot concepts that I knew before about ViewModels, LiveData and stuff. Am I breaking MVVM's architecture with my approach? What's the role of LiveData in this kind of logic attempt of mine? Can I read the SQL query result's length directly from some LiveData's method, or else, I should retrieve the list from it to do so?

我想真正的问题是:我的方法有错吗?根据用户搜索的长度,实现片段逻辑的最简洁方法是什么?

I guess the actual question is: is my approach wrong? What would be the cleanest way to implement my fragment's logic depending on user search's length?

我不只是问好的做法(仍然受欢迎);我几乎没有为这个应用程序投入 7 个小时,我仍然无法构建第一个 alpha 版本来开始测试它.短期内我的首要任务是把这件事放在一起(我可能会加上我自己);换句话说:首先,即使它不干净,我也想让它工作.现在我是一只头脑简单的猴子,它只是认为这是一个普通的 PC 应用程序,我不必在应用程序生命周期、多线程和所有相关的东西中挣扎,我只需要检索 SQL 查询的结果马上.请原谅我的无知.

I am not asking only about good practices (which are still welcome); I have barely dedicated 7 hours to this app yet and I couldn't still build a first alpha version to start testing it. My first priority in short-term is putting this thing together (and myself together I might add); in other words: first, I want to make it work even if it is not clean. Right now I am a simple-minded monkey which just thinks about this like if this was a normal PC app in which I don't have to struggle with App lifecycles, multithreading and all related stuff,in which I just retrieve the SQL query's result right away. I beg your pardon for my ignorance.

因此,为了添加有关我正在尝试执行的操作的更多上下文:如果 searxh 结果为零,则 fragmentA 将是向表中添加新行的表单;fragmentB 将只显示第一行的数据,尚未列出(我最终会到达那里,但还没有).

So, in order to add more context about what I am trying to do: If searxh results are zero, fragmentA would be a form for adding a new row to the table; fragmentB would show just the data of the first row, not listing yet (I will reach there eventually, but not yet).

推荐答案

这是我最终实现我提出问题时所想到的逻辑的方式.但这并不意味着这是一种干净的方式.

Here is the way I ended up implementing the logic I had in mind when I made the question. But that doesn't mean this is the clean way to do it.

为了获得用户查询的大小,我最终使用了一个观察者(正如 Teo 在他的评论中所说).我不确定是否将 Observer 和 LiveData 用于仅在手机应用程序本地(因此只能由应用程序用户自己修改)的数据库,以便在用户每次点击搜索"时获取查询结果.按钮,我不确定使用 Oberser 和 LiveData 是否有点矫枉过正……以及使用 DatabaseClient(RoomDatabase 的单例)作为存储库的异常?不再......我创建了一个专用的存储库类来处理 DatabaseClient 和 DAO.

In order to get the size of the User query, I ended up using an Observer (as Teo said in his comment). I am not sure if using Observer and LiveData for a Database that is merely local in the phone's app (and therefore shall only be modified by the App's user himself) for obtaining query results each time the user hits "Search" button, I am not sure if using Oberser and LiveData for this is overkill or not... and the aberration of using DatabaseClient (the RoomDatabase's singleton) as a Repository? Not anymore... I have created a dedicated Repository Class to handle the DatabaseClient and the DAOs.

也就是说,我的 Repository 类的相关部分:

That said, the relevant part of my Repository class:

public class Repository {
    private final TableRowDao tablerow_dao;

    public Repository(Application application) {
        AppDatabase app_db = DatabaseClient.getInstance(application).getAppDatabase();
        tablerow_dao = app_db.tableRowDao();
    }

    public LiveData<List<TableRow>> getFilteredList(String search) {
        return tablerow_dao.filteredSearch(search);
    }
    // [...]

...这里,ViewModel:

...here, the ViewModel:

public class TableRowsViewModel extends AndroidViewModel {
private Repository repository;

public TableRowsViewModel(@NonNull Application application) {
    super(application);
    repository = new Repository(application);
}

public LiveData<List<TableRow>> getUserSearch(String search) {
    return repository.getFilteredList(search);
}

没有为此目的使用 AsyncTask.

在 MainActivity 中,在 OnCreate 方法中:

In MainActivity, within OnCreate method:

search_view.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        my_viewmodel = new TableRowsViewModel(getApplication());
        search_results = my_viewmodel.getUserSearch(query);

        observeSearchResults(search_results);
        return true;
    }

    // [...]
});

ObserveSearchResults 也是我在 MainActivity 中声明的私有方法:

ObserveSearchResults is a private method that I declared in MainActivity as well:

// Having a observer is good and stuff, but am I overdoing it?
private void observeSearchResults(LiveData<List<TableRow>> search_results) {
    search_results.observe(this, new Observer<List<TableRow>>() {
        @Override
        public void onChanged(List<TableRow> rows) {
            if ( rows.size() > 0 ) {
                // TODO I don't list the results yet, I show the first one right away
                profileFragment = ProfileFragment.newInstance(rows.get(0));
                transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.fragmentContainer, profileFragment);
                transaction.addToBackStack(null);
                transaction.commit();
            } else {
                transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.fragmentContainer, insertFragment);
                transaction.addToBackStack(null);
                transaction.commit();
            }
        }
    });
}

这对我有用,但这并不意味着我以一种干净的方式做这件事.

这篇关于在 MVVM 架构中检查 SELECT 查询结果长度的干净方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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