Snippets
Nemanja B Sample LiveData with features like loaders. Content observer, load queuing, throttling. Cancellation not implemented.
Created by
Nemanja B
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | /*
* Copyright (C) 2018 Sony Mobile Communications Inc.
* All rights, including trade secret rights, reserved.
*/
package com.sonymobile.emailcommon.provider;
import android.annotation.SuppressLint;
import android.arch.lifecycle.LiveData;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import com.sonymobile.mail.log.Elog;
import java.lang.ref.WeakReference;
import java.util.concurrent.Executor;
/**
* TODO Write doc
*/
public class EmailContentLiveData<T extends EmailContent> extends LiveData<T> {
static Executor sExecutor = AsyncTask.THREAD_POOL_EXECUTOR;
private final Executor mExecutor = sExecutor;
private final Context mContext;
private final Uri mContentUri;
private final long mId;
private final Class<T> mEmailContentClass;
private final Throttle mThrottle;
private final String[] mProjection;
private ForceLoadContentObserver mForceLoadContentObserver;
private boolean mPending = true;
private ContentResolver mContentResolver;
private Task mExecutingTask;
private boolean mIsActive = false;
public EmailContentLiveData(Context context, Uri contentUri, long id,
Class<T> emailContentClass, String[] projection) {
mContext = context.getApplicationContext();
mContentUri = contentUri;
mId = id;
mEmailContentClass = emailContentClass;
mThrottle = new Throttle("LiveData:" + emailContentClass.getName(),
this::executePendingTask, new Handler());
mProjection = projection;
}
@Override
protected void onActive() {
super.onActive();
if (mForceLoadContentObserver == null) {
mForceLoadContentObserver = new ForceLoadContentObserver(this);
mContentResolver = mContext.getContentResolver();
mContentResolver
.registerContentObserver(mContentUri, true, mForceLoadContentObserver);
}
mIsActive = true;
executePendingTask();
}
@Override
protected void onInactive() {
super.onInactive();
mIsActive = false;
}
@Override
protected void finalize() throws Throwable {
// This might be the only way
try {
if (mForceLoadContentObserver != null) {
Elog.w(EmailContentLiveData.class, "finalize: ");
mContentResolver.unregisterContentObserver(mForceLoadContentObserver);
mForceLoadContentObserver = null;
}
} finally {
super.finalize();
}
}
private void executePendingTask() {
boolean execute = mPending && mExecutingTask == null && mIsActive;
if (execute) {
// no cancellation yet
mExecutingTask = new Task(getValue());
mExecutingTask.executeOnExecutor(mExecutor);
mPending = false;
}
}
private T executeInBackground() {
return EmailContent.restoreContentWithId(mContext, mEmailContentClass, mContentUri,
mProjection, mId, null);
}
static class ForceLoadContentObserver extends ContentObserver {
private final WeakReference<EmailContentLiveData> mWeakReference;
public ForceLoadContentObserver(EmailContentLiveData liveData) {
super(new Handler());
mWeakReference = new WeakReference<>(liveData);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
EmailContentLiveData liveData = mWeakReference.get();
if (liveData != null) {
liveData.mPending = true;
liveData.mThrottle.onEvent();
}
}
}
@SuppressLint("StaticFieldLeak")
class Task extends AsyncTask<Void, Void, Pair<T, Boolean>> {
@Nullable
private final T mValue;
public Task(@Nullable T value) {
mValue = value;
}
@Override
protected final Pair<T, Boolean> doInBackground(Void... voids) {
T t = executeInBackground();
if (mValue != null && t != null) {
return Pair.create(t, t.toContentValues().equals(mValue.toContentValues()));
}
return Pair.create(t, Boolean.FALSE);
}
@Override
protected void onPostExecute(Pair<T, Boolean> pair) {
super.onPostExecute(pair);
if (!pair.second) {
setValue(pair.first);
}
mExecutingTask = null;
// If changed in the mean time
executePendingTask();
}
@Override
protected void onCancelled() {
super.onCancelled();
mExecutingTask = null;
}
}
}
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.