Skip to content

Instantly share code, notes, and snippets.

@ok3141
Last active January 23, 2020 11:48
Show Gist options
  • Save ok3141/c28a5de8d39e5e67bce7ba2587917460 to your computer and use it in GitHub Desktop.
Save ok3141/c28a5de8d39e5e67bce7ba2587917460 to your computer and use it in GitHub Desktop.
Java implementation of Promise based on LiveData + lambda in Android
import android.os.Handler;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.arch.core.util.Function;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
public class Promise<T> {
@NonNull
protected final LiveData<T> liveData;
private Promise(@NonNull LiveData<T> liveData) {
this.liveData = liveData;
}
@Nullable
public T getValue() {
return liveData.getValue();
}
/**
* Observe changes for only one occurrence.
*/
@NonNull
public <R> Promise<R> once(
@NonNull LifecycleOwner lifecycleOwner,
@NonNull final Function<T, R> function
) {
final MutableLiveData<R> result = new MutableLiveData<>();
liveData.observe(lifecycleOwner, new Observer<T>() {
@Override
public void onChanged(@Nullable T t) {
liveData.removeObserver(this);
result.setValue(function.apply(t));
}
});
return Promise.wrap(result);
}
/**
* Observe changes for only one occurrence and then invoke given <code>function</code>.
*/
@NonNull
public <R> Promise<R> then(
@NonNull final LifecycleOwner lifecycleOwner,
@NonNull final Function<T, Promise<R>> function
) {
final MutableLiveData<R> result = new MutableLiveData<>();
liveData.observe(lifecycleOwner, new Observer<T>() {
@Override
public void onChanged(@Nullable final T t) {
liveData.removeObserver(this);
Promise<R> promise = function.apply(t);
if (promise != null) {
promise.once(lifecycleOwner, r -> {
result.setValue(r);
return null;
});
} else {
result.setValue(null);
}
}
});
return Promise.wrap(result);
}
/**
* Observe changes for only one occurrence and then invoke given <code>function</code>.
* Result is combined into a {@link Pair}.
*/
@NonNull
public <R> Promise<Pair<T, R>> thenPair(
@NonNull final LifecycleOwner lifecycleOwner,
@NonNull final Function<T, Promise<R>> function
) {
final MutableLiveData<Pair<T, R>> result = new MutableLiveData<>();
liveData.observe(lifecycleOwner, new Observer<T>() {
@Override
public void onChanged(@Nullable final T t) {
liveData.removeObserver(this);
Promise<R> promise = function.apply(t);
if (promise != null) {
promise.once(lifecycleOwner, r -> {
result.setValue(new Pair<>(t, r));
return null;
});
} else {
result.setValue(new Pair<>(t, null));
}
}
});
return Promise.wrap(result);
}
@NonNull
public static <V> Promise<V> wrap(@NonNull LiveData<V> value) {
return new Promise<>(value);
}
@NonNull
public static <V> Promise<V> value(@Nullable V value) {
MutableLiveData<V> liveData = new MutableLiveData<>();
liveData.setValue(value);
return wrap(liveData);
}
@NonNull
public static <A, V> Promise<V> async(@NonNull Executor executor, @NonNull final Function<A, V> function, @Nullable final A arg) {
final MutableLiveData<V> result = new MutableLiveData<>();
executor.execute(() -> result.postValue(function.apply(arg)));
return wrap(result);
}
@NonNull
public static Promise<Void> atTime(@NonNull Handler handler, long uptimeMillis) {
final MutableLiveData<Void> result = new MutableLiveData<>();
handler.postAtTime(() -> result.postValue(null), uptimeMillis);
return wrap(result);
}
@NonNull
@SuppressWarnings("unchecked")
public static Promise<Object[]> all(@NonNull LifecycleOwner lifecycleOwner, @NonNull Promise... promises) {
final MutableLiveData<Object[]> result = new MutableLiveData<>();
final int n = promises.length;
final Object[] array = new Object[n];
final AtomicInteger counter = new AtomicInteger();
for (int i = 0; i < n; ++i) {
final int index = i;
promises[i].once(lifecycleOwner, value -> {
array[index] = value;
if (counter.incrementAndGet() == n) {
result.setValue(array);
}
return null;
});
}
return Promise.wrap(result);
}
@NonNull
public static <T> Promise<List<T>> all(@NonNull LifecycleOwner lifecycleOwner, @NonNull List<Promise<T>> promises) {
final MutableLiveData<List<T>> result = new MutableLiveData<>();
final int n = promises.size();
final SortedMap<Integer, T> map = new TreeMap<>();
final AtomicInteger counter = new AtomicInteger();
for (int i = 0; i < n; ++i) {
final int index = i;
promises.get(i).once(lifecycleOwner, value -> {
map.put(index, value);
if (counter.incrementAndGet() == n) {
result.setValue(new ArrayList<>(map.values()));
}
return null;
});
}
return Promise.wrap(result);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment