如何使用 SQLite Database.Cursor Factory
Posted
技术标签:
【中文标题】如何使用 SQLite Database.Cursor Factory【英文标题】:How to use SQLiteDatabase.CursorFactory 【发布时间】:2012-07-08 16:44:58 【问题描述】:有人了解如何在 android 上使用 SQLiteDatabase.CursorFactory
吗?我希望获得一个持久的 SQLiteCursor 对象,该对象使用 SQL SELECT 语句,其中几个 WHERE 子句表达式使用可以在重新查询之前以编程方式更改的参数。
例如:
SELECT LocationID FROM Locations WHERE Latitude < northlimit AND Latitude > southlimit AND Longitude < eastlimit AND Longitude > westlimit;
限制参数会动态变化,每 200 毫秒一次
我正在尝试解决一个问题,即如果我只使用SQLiteDatabase.rawQuery("SELECT ...");
,系统会为每个新查询创建一个新的 CursorWindow,最终内存不足。所以我试图找到一种方法来强制系统不要创建新的 CursorWindows。
【问题讨论】:
在重新查询之前,您应该关闭旧光标。这样你就不会耗尽内存。据我所知,SQLite 不支持对其查询结果集的随机行访问。您只能从头到尾迭代 SQLite 结果。 Android 框架通过将整个结果加载到游标中以允许随机访问来解决该问题。如果您的查询返回很多行(或大量数据),您也可能会遇到内存不足的情况。 【参考方案1】:您可以查看本教程.. 它完美地总结了它:
http://www.youtube.com/watch?v=j-IV87qQ00M
你应该关闭数据库,在任何使用后.. 另一种方法是创建类变量 Cursor cr 并且每次使用它时都检查一下: 如果(cr==null) cr = 新 .... 否则//做某事//
cr.close();
【讨论】:
【参考方案2】:我不认为使用 CursorFactory 会有所帮助或不需要。
在以下示例中,基于您的表格创建并加载了 100000 行。
单个游标用于每 50 毫秒提取可变数量的行 10000 次。
当返回游标时,获得计数(导致扫描游标并因此访问数据库)并更新 TextView,显示迭代和获得的行数。
应用程序运行时不会崩溃,并且分析器显示内存正在按以下方式进行管理:-
使用的代码是:-
数据库助手:-
public class DBHelper extends SQLiteOpenHelper
public static final String DBNAME = "mydb";
public static final int DBVERSION = 1;
public static final String TBL_LOCATIONS = "Locations";
public static final String COl_LOCATIONS_ID = "LocationId";
public static final String COl_LATITUDE = "Lattitude";
public static final String COl_LONGITUDE = "Longitude";
public static final String COL_OTHER = "other";
public DBHelper(@Nullable Context context)
super(context, DBNAME, null, DBVERSION);
@Override
public void onCreate(SQLiteDatabase db)
db.execSQL("CREATE TABLE IF NOT EXISTS " + TBL_LOCATIONS +
"(" +
COl_LOCATIONS_ID + " INTEGER PRIMARY KEY," +
COl_LATITUDE + " REAL," +
COl_LONGITUDE + " REAL," +
COL_OTHER + " TEXT," +
" UNIQUE(" + COl_LONGITUDE + "," + COl_LATITUDE + ")" +
")"
);
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
public long insertLocation(double longitude, double latitude, String other)
ContentValues cv = new ContentValues();
cv.put(COl_LONGITUDE,longitude);
cv.put(COl_LATITUDE,latitude);
cv.put(COL_OTHER,other);
return this.getWritableDatabase().insert(TBL_LOCATIONS,null,cv);
public Cursor getLocations(double northlimit, double southlimt, double eastlimit, double westlimit)
return this.getWritableDatabase().query(
TBL_LOCATIONS,
new String[]COl_LOCATIONS_ID,
COl_LATITUDE + " <? AND " + COl_LATITUDE + ">? AND " + COl_LONGITUDE + "<? AND " + COl_LONGITUDE + "<?",
new String[]
String.valueOf(northlimit),
String.valueOf(southlimt),
String.valueOf(eastlimit),
String.valueOf(westlimit),
null,null,null );
活动是:-
public class MainActivity extends AppCompatActivity
private int mInterval = 50;
private int mCounter = 0;
private final int mLimit = 10000;
private Handler mHandler;
private DBHelper mDBHlpr;
private Cursor mCsr; //<<<<<<<<<< Just this 1 Cursor is used.
TextView mTV;
Random mRnd;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTV = this.findViewById(R.id.tv);
mRnd = new Random();
mDBHlpr = new DBHelper(this);
addSomeDataIfNone();
mHandler = new Handler();
mRunIt.run();
private void addSomeDataIfNone()
SQLiteDatabase db = mDBHlpr.getWritableDatabase();
if (DatabaseUtils.queryNumEntries(db,DBHelper.TBL_LOCATIONS) > 0) return;
Random rnd = new Random();
db.beginTransaction();
for (int i=0; i < 100000; i++ )
mDBHlpr.insertLocation(abs(mRnd.nextDouble()),abs(mRnd.nextDouble()),"LOCATION" + String.valueOf(i));
db.setTransactionSuccessful();
db.endTransaction();
Runnable mRunIt = new Runnable()
@Override
public void run()
if (mCounter > mLimit) return;
getData(mCounter);
mCounter++;
mHandler.postDelayed(mRunIt, mInterval);
;
private void getData(int iteration)
Log.d("GETTINGDATA","Getting data for iteration " + String.valueOf(iteration));
double latlim1 = abs(mRnd.nextDouble());
double latlim2 = abs(mRnd.nextDouble());
double lnglim1 = abs(mRnd.nextDouble());
double lnglim2 = abs(mRnd.nextDouble());
double nlim = 0.0, slim = 0.0, elim = 0.0, wlim = 0.0;
if (latlim1 > latlim2)
nlim = latlim1;
slim = latlim2;
else
nlim = latlim2;
slim = latlim1;
if (lnglim1 > lnglim2)
elim = lnglim1;
wlim = lnglim2;
else
elim = lnglim2;
wlim = lnglim1;
mCsr = mDBHlpr.getLocations(nlim,slim,elim,wlim);
mTV.setText("Iteration " + String.valueOf(iteration) + " Rows returned = " + String.valueOf(mCsr.getCount()));
【讨论】:
以上是关于如何使用 SQLite Database.Cursor Factory的主要内容,如果未能解决你的问题,请参考以下文章