Last active
January 23, 2020 11:48
-
-
Save ok3141/c28a5de8d39e5e67bce7ba2587917460 to your computer and use it in GitHub Desktop.
Java implementation of Promise based on LiveData + lambda in Android
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.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