Created
March 11, 2018 14:01
-
-
Save cbeyls/de3a0d0bc4a5a5572393a3a106971fc1 to your computer and use it in GitHub Desktop.
A LiveData class that can be invalidated & computed on demand (based on an internal architecture components class)
This file contains 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
package be.digitalia.arch.lifecycle; | |
import android.arch.lifecycle.LiveData; | |
import android.arch.lifecycle.MutableLiveData; | |
import android.os.AsyncTask; | |
import android.support.annotation.MainThread; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.VisibleForTesting; | |
import android.support.annotation.WorkerThread; | |
import java.util.concurrent.atomic.AtomicBoolean; | |
/** | |
* A LiveData class that can be invalidated & computed on demand. | |
* | |
* @param <T> The type of the live data | |
*/ | |
public abstract class ComputableLiveData<T> { | |
private final MutableLiveData<T> mLiveData; | |
private final AtomicBoolean mInvalid = new AtomicBoolean(true); | |
private final AtomicBoolean mComputing = new AtomicBoolean(false); | |
/** | |
* Creates a computable live data which is computed when there are active observers. | |
* <p> | |
* It can also be invalidated via {@link #invalidate()} which will result in a call to | |
* {@link #compute()} if there are active observers (or when they start observing) | |
*/ | |
public ComputableLiveData() { | |
mLiveData = new MutableLiveData<T>() { | |
@Override | |
protected void onActive() { | |
AsyncTask.THREAD_POOL_EXECUTOR.execute(mRefreshRunnable); | |
} | |
}; | |
} | |
/** | |
* Returns the LiveData managed by this class. | |
* | |
* @return A LiveData that is controlled by ComputableLiveData. | |
*/ | |
@NonNull | |
public LiveData<T> getLiveData() { | |
return mLiveData; | |
} | |
@VisibleForTesting | |
final Runnable mRefreshRunnable = new Runnable() { | |
@WorkerThread | |
@Override | |
public void run() { | |
boolean computed; | |
do { | |
computed = false; | |
if (mComputing.compareAndSet(false, true)) { | |
try { | |
T value = null; | |
while (mInvalid.compareAndSet(true, false)) { | |
computed = true; | |
value = compute(); | |
} | |
if (computed) { | |
mLiveData.postValue(value); | |
} | |
} finally { | |
mComputing.set(false); | |
} | |
} | |
} while (computed && mInvalid.get()); | |
} | |
}; | |
/** | |
* Invalidates the LiveData. | |
* <p> | |
* When there are active observers, this will trigger a call to {@link #compute()}. | |
*/ | |
@MainThread | |
public void invalidate() { | |
boolean isActive = mLiveData.hasActiveObservers(); | |
if (mInvalid.compareAndSet(false, true)) { | |
if (isActive) { | |
AsyncTask.THREAD_POOL_EXECUTOR.execute(mRefreshRunnable); | |
} | |
} | |
} | |
@SuppressWarnings("WeakerAccess") | |
@WorkerThread | |
protected abstract T compute(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment