Last active
March 7, 2020 09:00
-
-
Save GBouerat/f1afd638de785e46d89520a86334f964 to your computer and use it in GitHub Desktop.
First try at LiveData with Cursor and ContentProvider to keep using CursorAdapter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Application; | |
import android.arch.lifecycle.LiveData; | |
import android.content.Context; | |
import android.database.ContentObserver; | |
import android.database.Cursor; | |
import android.net.Uri; | |
import android.os.AsyncTask; | |
import android.os.Handler; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.v4.content.ContentResolverCompat; | |
import android.support.v4.os.CancellationSignal; | |
import android.support.v4.os.OperationCanceledException; | |
import android.util.Log; | |
public abstract class CursorLiveData | |
extends LiveData<Cursor> { | |
private static final String TAG = "CursorLiveData"; | |
@NonNull | |
private final Context mContext; | |
@NonNull | |
private final ForceLoadContentObserver mObserver; | |
@Nullable | |
private CancellationSignal mCancellationSignal; | |
public CursorLiveData(@NonNull Application application) { | |
super(); | |
mContext = application.getApplicationContext(); | |
mObserver = new ForceLoadContentObserver(); | |
} | |
@Nullable | |
public abstract String[] getCursorProjection(); | |
@Nullable | |
public abstract String getCursorSelection(); | |
@Nullable | |
public abstract String[] getCursorSelectionArgs(); | |
@Nullable | |
public abstract String getCursorSortOrder(); | |
@NonNull | |
public abstract Uri getCursorUri(); | |
private void loadData() { | |
loadData(false); | |
} | |
private void loadData(boolean forceQuery) { | |
Log.d(TAG, "loadData()"); | |
if (!forceQuery) { | |
Cursor cursor = getValue(); | |
if (cursor != null | |
&& !cursor.isClosed()) { | |
return; | |
} | |
} | |
new AsyncTask<Void, Void, Cursor>() { | |
@Override | |
protected Cursor doInBackground(Void... params) { | |
try { | |
synchronized (CursorLiveData.this) { | |
mCancellationSignal = new CancellationSignal(); | |
} | |
try { | |
Cursor cursor = ContentResolverCompat.query( | |
mContext.getContentResolver(), | |
getCursorUri(), | |
getCursorProjection(), | |
getCursorSelection(), | |
getCursorSelectionArgs(), | |
getCursorSortOrder(), | |
mCancellationSignal | |
); | |
if (cursor != null) { | |
try { | |
// Ensure the cursor window is filled. | |
cursor.getCount(); | |
cursor.registerContentObserver(mObserver); | |
} catch (RuntimeException ex) { | |
cursor.close(); | |
throw ex; | |
} | |
} | |
return cursor; | |
} finally { | |
synchronized (CursorLiveData.this) { | |
mCancellationSignal = null; | |
} | |
} | |
} catch (OperationCanceledException e) { | |
if (hasActiveObservers()) { | |
throw e; | |
} | |
return null; | |
} | |
} | |
@Override | |
protected void onPostExecute(Cursor cursor) { | |
setValue(cursor); | |
} | |
}.execute(); | |
} | |
@Override | |
protected void onActive() { | |
Log.d(TAG, "onActive()"); | |
loadData(); | |
} | |
@Override | |
protected void onInactive() { | |
Log.d(TAG, "onInactive()"); | |
synchronized (CursorLiveData.this) { | |
if (mCancellationSignal != null) { | |
mCancellationSignal.cancel(); | |
} | |
} | |
} | |
@Override | |
protected void setValue(Cursor newCursor) { | |
Cursor oldCursor = getValue(); | |
if (oldCursor != null) { | |
Log.d(TAG, "setValue() oldCursor.close()"); | |
oldCursor.close(); | |
} | |
super.setValue(newCursor); | |
} | |
public final class ForceLoadContentObserver | |
extends ContentObserver { | |
public ForceLoadContentObserver() { | |
super(new Handler()); | |
} | |
@Override | |
public boolean deliverSelfNotifications() { | |
return true; | |
} | |
@Override | |
public void onChange(boolean selfChange) { | |
Log.d(TAG, "ForceLoadContentObserver.onChange()"); | |
loadData(true); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Application; | |
import android.arch.lifecycle.AndroidViewModel; | |
import android.database.Cursor; | |
import android.support.annotation.NonNull; | |
import android.util.Log; | |
import com.pepper.apps.android.livedata.base.CursorLiveData; | |
public abstract class CursorViewModel<D extends CursorLiveData> | |
extends AndroidViewModel { | |
private static final String TAG = "CursorViewModel"; | |
@NonNull | |
protected final D mCursorLiveData; | |
public CursorViewModel(@NonNull Application application) { | |
super(application); | |
mCursorLiveData = createCursorLiveData(application); | |
} | |
@NonNull | |
protected abstract D createCursorLiveData(@NonNull Application application); | |
@Override | |
protected void onCleared() { | |
Cursor cursor = mCursorLiveData.getValue(); | |
if (cursor != null) { | |
Log.d(TAG, "onCleared() cursor.close()"); | |
cursor.close(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment