Skip to content

Instantly share code, notes, and snippets.

@boxme
Created March 24, 2015 02:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boxme/c2878219dd5f01279425 to your computer and use it in GitHub Desktop.
Save boxme/c2878219dd5f01279425 to your computer and use it in GitHub Desktop.
PagerAdapter that uses uses Cursor as its data format
public abstract class CursorPagerAdapter extends PagerAdapter {
public static final String TAG = CursorPagerAdapter.class.getSimpleName();
protected WeakReference<Context> ctxRef;
protected boolean mDataValid;
protected boolean mAutoRequery;
protected Cursor mCursor;
protected int mRowIDColumn;
protected ChangeObserver mChangeObserver;
protected DataSetObserver mDataSetObserver;
/**
* If set the adapter will call requery() on the cursor whenever a content change notification is
* delivered. Implies {@link #FLAG_REGISTER_CONTENT_OBSERVER}.
*
* @deprecated This option is discouraged, as it results in Cursor queries being performed on the
* application's UI thread and thus can cause poor responsiveness or even Application
* Not Responding errors. As an alternative, use {@link android.app.LoaderManager} with
* a {@link android.content.CursorLoader}.
*/
@Deprecated
public static final int FLAG_AUTO_REQUERY = 0x01;
/**
* If set the adapter will register a content observer on the cursor and will call {@link
* # onContentChanged()} when a notification comes in. Be careful when using this flag: you will
* need to unset the current Cursor from the adapter to avoid leaks due to its registered
* observers. This flag is not needed when using a CursorAdapter with a {@link
* android.content.CursorLoader}.
*/
public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02;
public CursorPagerAdapter(Context context, Cursor c, int flags) {
init(context, c, flags);
}
void init(Context context, Cursor c, int flags) {
if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) {
flags |= FLAG_REGISTER_CONTENT_OBSERVER;
mAutoRequery = true;
} else {
mAutoRequery = false;
}
boolean cursorPresent = c != null;
mCursor = c;
mDataValid = cursorPresent;
ctxRef = new WeakReference<>(context);
mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
mChangeObserver = new ChangeObserver();
mDataSetObserver = new MyDataSetObserver();
} else {
mChangeObserver = null;
mDataSetObserver = null;
}
if (cursorPresent) {
if (mChangeObserver != null) {
c.registerContentObserver(mChangeObserver);
}
if (mDataSetObserver != null) {
c.registerDataSetObserver(mDataSetObserver);
}
}
}
public Cursor getCursor() {
return mCursor;
}
@Override
public int getCount() {
if (mDataValid && mCursor != null)
return mCursor.getCount();
else
return 0;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (!mDataValid) {
throw new IllegalStateException("this should only be called when the cursor is valid");
}
if (!mCursor.moveToPosition(position)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
Context context = ctxRef.get();
if (context != null) {
View v = newView(context, mCursor, (ViewGroup) container);
bindView(v, context, mCursor);
((ViewPager) container).addView(v);
return v;
} else {
throw new IllegalStateException("context is null");
}
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public boolean isViewFromObject(View view, Object o) {
return view == o;
}
public abstract View newView(Context context, Cursor cursor, ViewGroup parent);
public abstract void bindView(View view, Context context, Cursor cursor);
public void changeCursor(Cursor cursor) {
Cursor old = swapCursor(cursor);
if (old != null) {
old.close();
}
}
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == mCursor) return null;
Cursor oldCursor = mCursor;
if (oldCursor != null) {
if (mChangeObserver != null) {
oldCursor.unregisterContentObserver(mChangeObserver);
}
if (mDataSetObserver != null) {
oldCursor.unregisterDataSetObserver(mDataSetObserver);
}
}
mCursor = newCursor;
if (newCursor != null) {
if (mChangeObserver != null) {
newCursor.registerContentObserver(mChangeObserver);
}
if (mDataSetObserver != null) {
newCursor.registerDataSetObserver(mDataSetObserver);
}
mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
mDataValid = true;
// notify the observers about the new cursor
notifyDataSetChanged();
} else {
mRowIDColumn = -1;
mDataValid = false;
notifyDataSetChanged();
}
return oldCursor;
}
private void onContentChange() {
if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
mDataValid = mCursor.requery();
}
}
private class ChangeObserver extends ContentObserver {
public ChangeObserver() {
super(new Handler());
}
/**
*
* @return True if self-change notifications should be delivered to the observer.
*/
@Override
public boolean deliverSelfNotifications() {
return true;
}
/**
* This method is called when a content change occurs.
* @param selfChange
*/
@Override
public void onChange(boolean selfChange) {
onContentChange();
}
}
private class MyDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
mDataValid = true;
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
mDataValid = false;
notifyDataSetChanged();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment