如何在后台线程上异步运行SQLite查询? [英] How to run SQLite query asynchronously on background thread?

查看:291
本文介绍了如何在后台线程上异步运行SQLite查询?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的数据库很大,需要一些时间才能找到所需的信息.因此,我决定使用RxJava使该过程异步.

I have a big database which takes time to find needed information. So I decided to use RxJava to make this process asynchronous.

            @Override
        public void afterTextChanged(final Editable s) {
            final String query = s.toString();
            Observable.create(new Observable.OnSubscribe<Cursor>() {
                @Override
                public void call(Subscriber<? super Cursor> subscriber) {
                    subscriber.onNext(database.search(query));
                }
            }).subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<Cursor>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {
                    e.printStackTrace();
                }

                @Override
                public void onNext(Cursor cursor) {
                    scAdapter.swapCursor(cursor);
                }
            });
        }

但是查询正在主线程上运行:在我输入文本的EditText处冻结.

But query is running on main thread: EditText where I entering text is freezing.

我的问题是如何在后台线程上异步运行SQLite查询?

My question is how to run SQLite query asynchronously on background thread?

推荐答案

可能 https://developer.android.com/reference/android/app/LoaderManager.html 将为您提供服务.

Probably this https://developer.android.com/reference/android/app/LoaderManager.html will suite for you.

此外,这是为您提供的简短实现,但这不是RxJava.

Besides, here is short implementation for you, but this is not RxJava.

首先,您需要实现LoaderManager.LoaderCallbacks<Cursor>,通常此接口是由Activity(或Fragment)实现的.

Firstly, you need to implement LoaderManager.LoaderCallbacks<Cursor>, and usually this interface is implemented by Activity (or Fragment).

onCreateLoader中,应创建一个CursorLoader并返回.这只是MyCursorLoader作为CursorLoader的后代的示例,您可以在其中执行到数据库和查询的连接.

In onCreateLoader, a CursorLoader should be created and returned. Here is just an example with MyCursorLoader as descendant of CursorLoader, where you can perform connection to database and queries.

onLoadFinished中,您必须将游标与查询结果一起使用.

In onLoadFinished you have to treat cursor with results of query.

请考虑上面提到的android.com链接.

Please, consider the link to android.com, mentioned above.

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

@Override
protected void onResume() {
    super.onResume();

    // start loading data using LoaderManager of Activity
    // third argument only has sense in this case
    getLoaderManager().initLoader(0, null, this);
}

private static final String ACTIVITY_NAME = "main_activity";

private void treatCursorRow(Cursor cursor){
    // treat record from cursor
}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // this callback is called by LoaderManager in order to obtain CursorLoader
    // here a new one loader is created
    // created loader will be processed by LoaderManager
    return new MyCursorLoader(this, ACTIVITY_NAME);
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // this callback is called when loader finishes load cursor
    // you don't need to destroy loader - just tread the data
    if(data != null)
        while(data.moveToNext())
            treatCursorRow(data);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    // here you can do something
    // relevant to cancelling of loading data
    // in example, when you have an event that cancels current
    // loading and restarts new one
}

class MyCursorLoader extends CursorLoader {

    private static final String DATABASE_NAME = "my_database";
    private static final int DATABASE_VERSION = 1;
    private String name_param;

    public MyCursorLoader(Context context, String activity_name) {
        super(context);
        name_param = activity_name;
    }

    @Override
    public Cursor loadInBackground() {
        // assuming, that we have implemented SQLiteOpenHelper
        // to treat sqlite-database
        MyDatabaseHelper dbh = new MyDatabaseHelper(
                MainActivity.this,
                DATABASE_NAME,
                null,
                DATABASE_VERSION
        );
        return dbh.getWritableDatabase().rawQuery(
                "SELECT * FROM some_table WHERE name=?",
                new String[]{ name_param }
        );
    }

}

}

另一种方法是使用ContentProvider https://developer.android.com/guide/topics/providers/content-providers.html .

通过这种方式,您可以分离数据层和业务逻辑.您的数据访问将抽象为uris. 使用ContentProvider,您可以在其中定义查询并使用Uri加载数据:

In this way you can separate data layer and business logic. Your data access will be abstracted to uris. Using ContentProvider, you define your queries within it and load data using Uri:

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    return getContentResolver().query(
            YourContentProvider.SOME_URI,
            null,
            null,
            null,
            null
    );
}

如果您有一个或两个以上的数据客户(活动或片段),这是一种便捷的方法-您将仅使用预定义的uri,而不是重复sql查询或创建许多CursorLoaders descendands.

This is convenient way if you have more than one or two customers of your data (Activities or Fragments) - you will use just predefined uris rather repeating sql queries or creating many CursorLoaders descendands.

此外,如果需要,可以从应用程序外部使用ContentProvider.

Moreover, ContentProvider may be used from outside your app if you want.

这篇关于如何在后台线程上异步运行SQLite查询?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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