使用CursorLoader查询SQLite数据库并填充AutoCompleteTextView

15

我有一个SQLite数据库需要查询,我想将其作为目标针对Android 2.2到ICS。我找到了这篇文章,介绍了如何完成这个任务,但是它使用了已经被弃用的代码(不是异步查询而是在UI线程上进行查询)。后来我了解到可以使用CursorLoaderLoaderManager来完成此任务,这是一种首选和最佳实践的方式(以避免使UI线程过于繁忙)。

问题是是否存在一个简洁明了的示例来教我如何完成以下任务:1) 加载数据库,2) 查询数据库,3) 使用结果来填充一个AutoCompleteTextView列表视图?

是否存在这样的示例?


还在尝试寻找类似的例子。我找到的那些似乎都缺少光标。 - kpierce8
我正在这里做类似的事情! https://dev59.com/Y-o6XIcBkEYKwwoYPR_f - Etienne Lawlor
3个回答

1

我知道这是一个老问题,但对于访问此页面的人:

SimpleCursorAdapter有一个新的构造函数:

SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags)

这个构造函数不使用UI线程。您可以安全地使用它。


0

我现在手头上没有代码,但之前我问过一个类似的问题:

Android db loading chat for chat application

如果你仔细阅读它,你会发现如何使用CursorLoader来操作你的sqlite数据库;)


0
我创建了一个SQLiteHelper类。在我的情况下,如果不存在,我会将一个sqlite数据库从assets文件夹复制到/data/data目录中:
private DatabaseHelper(Context context, String name, CursorFactory factory,
        int version) {
    super(context, DB_NAME, null, 1);
    this.mContext = context;
}

// getInstance() singleton
public static synchronized DatabaseHelper getInstance(Context context) {
    if (_instance == null) {
        _instance = new DatabaseHelper(context,null,null,1);
    }
    return _instance;
}

@Override
public void onCreate(SQLiteDatabase db) {
    // Leave it blank, we don't want to create.

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // Leave it blank, we don't want to upgrade

}

public void createDataBase() throws IOException{

    boolean dbExist = checkDataBase();

    if(dbExist){
        openDataBase();
        // check the version number;
        SQLiteCursor cursor = runQuery("select versionNumber from version where VersionType = \"CURRENT\"");
        if (cursor!=null){
            cursor.moveToFirst();
            int version = cursor.getInt(cursor.getColumnIndex("versionNumber"));
            if (version!=SQL_VERSION){
                //TODO - grab the favorites and ingredients first.
                ArrayList<String> favorites = getFavorites();
                // I think I need to close the db before erasing it, then open new one.
                close();
                mContext.deleteDatabase(DB_NAME);
                this.getReadableDatabase();
                copyDataBase();
                openDataBase();
                for (int i = 0; i<favorites.size();i++){
                    insert(Constants.TABLE_FAVORITES,Constants.FAVORITE,favorites.get(i));
                }
                close();
            }
        }
    }else{
        //By calling this method and empty database will be created into the default system path
        //of your application so we are gonna be able to overwrite that database with our database.
        this.getReadableDatabase();

        copyDataBase();
    }
}

private void copyDataBase(){

    //Open your local db as the input stream
    InputStream myInput;
    try {
        myInput = mContext.getAssets().open(DB_NAME);
        // Path to the just created empty db
        String outFileName = LOCATION + DB_NAME;

        //Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(outFileName);

        //transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer))>0){
            myOutput.write(buffer, 0, length);
        }

        //Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

public void openDataBase() throws SQLException{
    //Open the database
    String myPath = LOCATION + DB_NAME;
    mDatabase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);

}

@Override
public synchronized void close() {
    if(mDatabase != null)
        mDatabase.close();
    super.close();
}

public SQLiteCursor runQuery(String query){
    return (SQLiteCursor) mDatabase.rawQuery(query,null);
}

private boolean checkDataBase(){

    SQLiteDatabase checkDB = null;

    try{
        String myPath = LOCATION + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    }catch(SQLiteException e){
        //database does't exist yet.
    }

    if(checkDB != null){
        checkDB.close();
    }

    return checkDB != null ? true : false;
}

// all insert does is insert to favorites and into your bar.
public void insert(String table, String column, String value) {
    ContentValues values = new ContentValues();
    values.put(column, value);
    mDatabase.insert(table, null, values);

}

public void delete(String table, String column, String value){
    mDatabase.delete(table,column+" = \""+value+"\"",null);
}

为了填充我的活动中的自动完成TextView:

startManagingCursor(mCursor);
    // get instance of database helper class
    mDatabaseHelper = DatabaseHelper.getInstance(this);
    // create database for first time
    try {
        mDatabaseHelper.createDataBase();
    } catch (IOException e) {
        //Log.i(TAG,"Could not create the database");
        e.printStackTrace();
    }
    // open the database
    mDatabaseHelper.openDataBase();
            mDrinks = this.populate();

填充方法:

//populates by drinks
private ArrayList<String> populate() {
    ArrayList<String> items = new ArrayList<String>();
    mCursor = mDatabaseHelper.runQuery(
            "select "+ Constants.TITLE +" from "
            +Constants.TABLE_DRINK+" order by "
            +Constants.TITLE);
    if (mCursor != null){
        mCursor.moveToFirst();
        while (!mCursor.isAfterLast()){
            items.add(mCursor.getString(mCursor.getColumnIndex(Constants.TITLE)));
            mCursor.moveToNext();
        }
    }
    return items;
}

然后我设置它:

// when text changes, autocomplete happens
    mSearchTextView = (AutoCompleteTextView) findViewById(R.id.search_drink);
    mSearchTextView.setAdapter(
            new ArrayAdapter<String>(
                    this, R.layout.list_item, mDrinks));
    mSearchTextView.setClickable(true);
    // clear the text when the searchTextView is clicked. Necessary for 
    // clearing after pressing enter in an invalid drink.
    mSearchTextView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            mSearchTextView.setText("");

        }
    });
    mSearchTextView.setOnItemClickListener(new OnItemClickListener(){

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long arg3) {
            // TODO - here we need to get the name, then search for ingredients and show everything in
            // an alert dialog. Here is main logic.
            buildDialog(parent.getItemAtPosition(position).toString());
        }

    });
    mSearchTextView.setOnEditorActionListener(new OnEditorActionListener() {

        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (event != null&& (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
                InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                in.hideSoftInputFromWindow(mSearchTextView
                        .getApplicationWindowToken(),
                        InputMethodManager.HIDE_NOT_ALWAYS);
                Toast.makeText(v.getContext(), "Please Select a Drink from the Auto Complete or the List Shown", Toast.LENGTH_LONG).show();
            }

            return false;
        }
    });

希望你能理解。我不能给你我的全部源代码,因为这是我开发的一个市场应用程序。在尝试完成所有工作之前,你可以先检查一下它: https://play.google.com/store/apps/details?id=com.life.plus.studios.bartender.drink.recipes.light

谢谢。我得去看看你的实现。我也喜欢你的应用程序! - mraviator
如果您有进一步的问题,请告诉我,因为我没有放完整的源代码,有些东西可能会令人困惑。 - Juan Acevedo
6
我想给它点个踩,但我声望不够,因为这个答案没有实现CursorLoader,而这是最佳实践并且也是问题所要求的。 - CraPo
@CraPo 我也想看到这个。一个教程或示例,其中您可以从资产文件夹中加载现有数据库(具有20多个表),然后使用LoaderManager、CursorLoader和ContentProvider在多个活动中执行查询。即使是Google的记事本示例也使用了上述(已弃用)方法... - Paranoid Android
@Jaun Acevedo 不错的应用,尽管你正在查询超过6000个条目的数据库,但我没有发现任何滞后。我也会这样做。当谷歌更新他们自己的教程以向我们展示如何更好地完成时,我会尝试一下。 - Paranoid Android

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接