使用 CursorLoader 查询 SQLite DB 并填充 AutoCompleteTextView
Posted
技术标签:
【中文标题】使用 CursorLoader 查询 SQLite DB 并填充 AutoCompleteTextView【英文标题】:Using CursorLoader to query SQLite DB and populate AutoCompleteTextView 【发布时间】:2012-04-12 08:00:43 【问题描述】:我有一个想要查询的 SQLite 数据库。我想通过 ICS 定位 android 2.2。我遇到了this 关于如何执行此操作的文章,但它使用了已弃用的代码(不异步查询,而是在 UI 线程上)。从那以后我读到我可以使用CursorLoader
和LoaderManager
来完成这项任务,这是首选的最佳实践方式(以免陷入UI线程)。
问题是找到一个简洁的例子来向我解释如何做到这一点。 1) 加载数据库,2) 查询它,3) 使用结果填充 AutoCompletetextBox 列表视图。
有这样的例子吗?
【问题讨论】:
也想找一个这样的例子。我发现的似乎没有光标。 我在这里做类似的事情!! ***.com/questions/12854336/… 【参考方案1】:我知道这是一个老问题,但对于访问此页面的人来说:
SimpleCursorAdapter 有一个新的构造函数:
SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags)
这个 cunstructor 不使用 UI 线程。您可以放心使用。
【讨论】:
【参考方案2】:我创建了一个 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
【讨论】:
谢谢。我将不得不检查您的实施。也喜欢你的应用! Np。如果您还有其他问题,请告诉我,因为我没有提供完整的来源,所以有些事情可能会令人困惑。 我会拒绝投票,但我没有足够的声誉,因为答案没有实现 CursorLoader,这是最佳实践,也是要求的。 @CraPo 我也想看看。一个教程或示例,您从资产文件夹(包含 20 多个表)加载现有数据库,然后使用 LoaderManager、CursorLoader 和 ContentProvider 在多个活动中执行查询。甚至 Google 的记事本示例也在使用上述(已弃用)方法... @Jaun Acevedo 不错的应用程序,尽管您正在查询包含 6000 多个条目的数据库,但我没有发现任何滞后。我也会走这条路。当 Google 会更新他们自己的教程以向我们展示如何做得更好时,我会试一试。【参考方案3】:我手头没有代码,但我之前问过类似的问题:
Android db loading chat for chat application
如果你仔细阅读,你会知道如何为你的 sqlite 数据库使用 CursorLoader ;)
【讨论】:
以上是关于使用 CursorLoader 查询 SQLite DB 并填充 AutoCompleteTextView的主要内容,如果未能解决你的问题,请参考以下文章
安卓:CursorLoader、LoaderManager、SQLite
android - 没有 Content Provider 的 CursorLoader 和 SQLite
当 CursorLoader 的构造函数不支持时,如何在 CursorLoader 中使用连接查询