源数据更改时加载器不加载数据
Android 文档指出 LOADERS - 它们监视数据源并在内容更改时提供新结果。我已更改 CursorAdapter 以适用于 SQLite 数据库。
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader.ForceLoadContentObserver;
import android.util.Log;
public class SimpleCursorLoader extends AsyncTaskLoader<Cursor> {
final ForceLoadContentObserver mObserver;
String mTable;
String[] mColumns;
String mSelection;
String[] mSelectionArgs;
String mGroupBy;
String mHaving;
String mOrderBy;
String mLimit;
Cursor mCursor;
SQLiteDatabase mDb;
/**
* Creates an empty unspecified CursorLoader. You must follow this with
* calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
* to specify the query to perform.
*/
public SimpleCursorLoader(Context context) {
super(context);
mObserver = new ForceLoadContentObserver();
}
/**
* Creates a fully-specified SimpleCursorLoader. See
* {@link ContentResolver#query(Uri, String[], String, String[], String)
* ContentResolver.query()} for documentation on the meaning of the
* parameters. These will be passed as-is to that call.
*/
public SimpleCursorLoader(Context context,String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having, String orderBy, String limit, SQLiteDatabase db) {
super(context);
mObserver = new ForceLoadContentObserver();
mTable = table;
mColumns = columns; //copying array
mSelection = selection;
mSelectionArgs = selectionArgs;
mGroupBy = groupBy;
mHaving = having;
mOrderBy = orderBy;
mLimit = limit;
mDb = db;
}
/* Runs on a worker thread */
@Override
public Cursor loadInBackground() {
Cursor cursor = mDb.query(mTable, mColumns, mSelection, mSelectionArgs, mGroupBy, mHaving, mOrderBy, mLimit);
if (cursor != null) {
// Ensure the cursor window is filled
cursor.getCount();
Log.d("SimpleCursorLoader","Cursor.getCount()= " + String.valueOf(cursor.getCount()));
registerContentObserver(cursor, mObserver);
}
return cursor;
}
/**
* Registers an observer to get notifications from the content provider
* when the cursor needs to be refreshed.
*/
void registerContentObserver(Cursor cursor, ContentObserver observer) {
cursor.registerContentObserver(mObserver);
}
/* Runs on the UI thread */
@Override
public void deliverResult(Cursor cursor) {
Log.d("Gaurav","Inside SimpleCursorLoader - deliverResult");
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
* will be called on the UI thread. If a previous load has been completed and is still valid
* the result may be passed to the callbacks immediately.
*
* Must be called from the UI thread
*/
@Override
protected void onStartLoading() {
Log.d("Gaurav", "onStartLoading");
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
}
CursorLoader 在带有自定义适配器的 ListFragment 中工作,该适配器扩展了 SimpleCursor Adapter 并在构造函数中传递 FLAG_REGISTER_CONTENT_OBSERVER,但当列表中使用的响应更改基础数据时,游标会发生变化。
Android Documentation states that LOADERS - They monitor the source of their data and deliver new results when the content changes. I have changed CursorAdapter to work for a SQLite Database.
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader.ForceLoadContentObserver;
import android.util.Log;
public class SimpleCursorLoader extends AsyncTaskLoader<Cursor> {
final ForceLoadContentObserver mObserver;
String mTable;
String[] mColumns;
String mSelection;
String[] mSelectionArgs;
String mGroupBy;
String mHaving;
String mOrderBy;
String mLimit;
Cursor mCursor;
SQLiteDatabase mDb;
/**
* Creates an empty unspecified CursorLoader. You must follow this with
* calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
* to specify the query to perform.
*/
public SimpleCursorLoader(Context context) {
super(context);
mObserver = new ForceLoadContentObserver();
}
/**
* Creates a fully-specified SimpleCursorLoader. See
* {@link ContentResolver#query(Uri, String[], String, String[], String)
* ContentResolver.query()} for documentation on the meaning of the
* parameters. These will be passed as-is to that call.
*/
public SimpleCursorLoader(Context context,String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having, String orderBy, String limit, SQLiteDatabase db) {
super(context);
mObserver = new ForceLoadContentObserver();
mTable = table;
mColumns = columns; //copying array
mSelection = selection;
mSelectionArgs = selectionArgs;
mGroupBy = groupBy;
mHaving = having;
mOrderBy = orderBy;
mLimit = limit;
mDb = db;
}
/* Runs on a worker thread */
@Override
public Cursor loadInBackground() {
Cursor cursor = mDb.query(mTable, mColumns, mSelection, mSelectionArgs, mGroupBy, mHaving, mOrderBy, mLimit);
if (cursor != null) {
// Ensure the cursor window is filled
cursor.getCount();
Log.d("SimpleCursorLoader","Cursor.getCount()= " + String.valueOf(cursor.getCount()));
registerContentObserver(cursor, mObserver);
}
return cursor;
}
/**
* Registers an observer to get notifications from the content provider
* when the cursor needs to be refreshed.
*/
void registerContentObserver(Cursor cursor, ContentObserver observer) {
cursor.registerContentObserver(mObserver);
}
/* Runs on the UI thread */
@Override
public void deliverResult(Cursor cursor) {
Log.d("Gaurav","Inside SimpleCursorLoader - deliverResult");
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
* will be called on the UI thread. If a previous load has been completed and is still valid
* the result may be passed to the callbacks immediately.
*
* Must be called from the UI thread
*/
@Override
protected void onStartLoading() {
Log.d("Gaurav", "onStartLoading");
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
}
The CursorLoader works in a ListFragment with a custom adapter which extends SimpleCursor Adapter and passes FLAG_REGISTER_CONTENT_OBSERVER in constructor but the cursor does changes when underlying data is changed by used response in the list.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我遇到了同样的问题,尽管我使用的实现与你不同。我能够通过将通知 URI 明确指定为不太具体的内容来纠正我的问题。我确信我的代码还存在其他问题,导致我需要这样做,但它解决了我的问题。因此,我的内容提供程序中的游标查询从:
到
MYURI 是 URI 类型的变量,我知道该变量将涵盖我正在观看的所有内容。
希望这可以帮助别人。
I had the same problem albeit I was using a different implementation than you. I was able to correct my problem by explicitly stating notification URI to something less specific. I'm sure there are other problems with my code that caused me to need to do this but it fixed my issue. So, my Cursor query in my content provider went from:
to
where MYURI is variable of the URI type that I know will cover everything I'm watching.
Hope this helps someone out.
您需要重写转储方法。
You need to override the dump method.