Browse Source

Prevent observers from sending events out of order, add documentation, annotations

master
Anthony Restaino 9 years ago
parent
commit
ac3f43a76f
  1. 2
      app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java
  2. 2
      app/src/main/java/acr/browser/lightning/activity/MainActivity.java
  3. 1
      app/src/main/java/acr/browser/lightning/async/ImageDownloadTask.java
  4. 9
      app/src/main/java/acr/browser/lightning/react/Action.java
  5. 64
      app/src/main/java/acr/browser/lightning/react/Observable.java
  6. 10
      app/src/main/java/acr/browser/lightning/react/Schedulers.java
  7. 20
      app/src/main/java/acr/browser/lightning/react/Subscriber.java
  8. 21
      app/src/main/java/acr/browser/lightning/react/Subscription.java
  9. 2
      app/src/main/java/acr/browser/lightning/view/LightningView.java

2
app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java

@ -20,7 +20,7 @@ public class IncognitoActivity extends BrowserActivity { @@ -20,7 +20,7 @@ public class IncognitoActivity extends BrowserActivity {
public Observable<Void> updateCookiePreference() {
return Observable.create(new Action<Void>() {
@Override
public void onSubscribe(Subscriber<Void> subscriber) {
public void onSubscribe(@NonNull Subscriber<Void> subscriber) {
CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(IncognitoActivity.this);

2
app/src/main/java/acr/browser/lightning/activity/MainActivity.java

@ -20,7 +20,7 @@ public class MainActivity extends BrowserActivity { @@ -20,7 +20,7 @@ public class MainActivity extends BrowserActivity {
public Observable<Void> updateCookiePreference() {
return Observable.create(new Action<Void>() {
@Override
public void onSubscribe(Subscriber<Void> subscriber) {
public void onSubscribe(@NonNull Subscriber<Void> subscriber) {
CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(MainActivity.this);

1
app/src/main/java/acr/browser/lightning/async/ImageDownloadTask.java

@ -17,7 +17,6 @@ import java.lang.ref.WeakReference; @@ -17,7 +17,6 @@ import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.URL;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.utils.Utils;

9
app/src/main/java/acr/browser/lightning/react/Action.java

@ -3,5 +3,14 @@ package acr.browser.lightning.react; @@ -3,5 +3,14 @@ package acr.browser.lightning.react;
import android.support.annotation.NonNull;
public interface Action<T> {
/**
* Should be overridden to send the subscriber
* events such as {@link Subscriber#onNext(Object)}
* or {@link Subscriber#onComplete()}.
*
* @param subscriber the subscriber that is sent in
* when the user of the Observable
* subscribes.
*/
void onSubscribe(@NonNull Subscriber<T> subscriber);
}

64
app/src/main/java/acr/browser/lightning/react/Observable.java

@ -3,6 +3,7 @@ package acr.browser.lightning.react; @@ -3,6 +3,7 @@ package acr.browser.lightning.react;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.concurrent.Executor;
@ -18,6 +19,8 @@ import acr.browser.lightning.utils.Preconditions; @@ -18,6 +19,8 @@ import acr.browser.lightning.utils.Preconditions;
*/
public class Observable<T> {
private static final String TAG = Observable.class.getSimpleName();
@NonNull private Action<T> mAction;
@Nullable private Executor mSubscriber;
@Nullable private Executor mObserver;
@ -30,54 +33,99 @@ public class Observable<T> { @@ -30,54 +33,99 @@ public class Observable<T> {
mDefault = new ThreadExecutor(looper);
}
/**
* Static creator method that creates an Observable from the
* {@link Action} that is passed in as the parameter. Action
* must not be null.
*
* @param action the Action to perform
* @param <T> the type that will be emitted to the subscriber
* @return a valid non-null Observable.
*/
@NonNull
public static <T> Observable<T> create(@NonNull Action<T> action) {
Preconditions.checkNonNull(action);
return new Observable<>(action);
}
/**
* Tells the Observable what Executor that the subscription
* work should run on.
*
* @param subscribeExecutor the Executor to run the work on.
* @return returns this so that calls can be conveniently chained.
*/
public Observable<T> subscribeOn(@NonNull Executor subscribeExecutor) {
mSubscriber = subscribeExecutor;
return this;
}
/**
* Tells the Observable what Executor the subscriber should observe
* the work on.
*
* @param observerExecutor the Executor to run to callback on.
* @return returns this so that calls can be conveniently chained.
*/
public Observable<T> observeOn(@NonNull Executor observerExecutor) {
mObserver = observerExecutor;
return this;
}
/**
* Subscribes immediately to the Observable and ignores
* all onComplete and onNext calls.
*/
public void subscribe() {
executeOnSubscriberThread(new Runnable() {
@Override
public void run() {
mAction.onSubscribe(new Subscriber<T>() {
@Override
public void onComplete() {
}
public void onComplete() {}
@Override
public void onNext(T item) {
}
public void onNext(T item) {}
});
}
});
}
/**
* Immediately subscribes to the Observable and starts
* sending events from the Observable to the {@link Subscription}.
*
* @param subscription the class that wishes to receive onNext and
* onComplete callbacks from the Observable.
*/
public void subscribe(@NonNull final Subscription<T> subscription) {
Preconditions.checkNonNull(subscription);
executeOnSubscriberThread(new Runnable() {
private boolean mOnCompleteExecuted = false;
@Override
public void run() {
mAction.onSubscribe(new Subscriber<T>() {
@Override
public void onComplete() {
executeOnObserverThread(new OnCompleteRunnable(subscription));
if (!mOnCompleteExecuted) {
mOnCompleteExecuted = true;
executeOnObserverThread(new OnCompleteRunnable(subscription));
} else {
Log.e(TAG, "onComplete called more than once");
throw new RuntimeException("onComplete called more than once");
}
}
@Override
public void onNext(final T item) {
executeOnObserverThread(new OnNextRunnable(subscription, item));
if (!mOnCompleteExecuted) {
executeOnObserverThread(new OnNextRunnable(subscription, item));
} else {
Log.e(TAG, "onComplete has been already called, onNext should not be called");
throw new RuntimeException("onNext should not be called after onComplete has been called");
}
}
});

10
app/src/main/java/acr/browser/lightning/react/Schedulers.java

@ -10,11 +10,21 @@ public class Schedulers { @@ -10,11 +10,21 @@ public class Schedulers {
private static final Executor sWorker = Executors.newCachedThreadPool();
private static final Executor sMain = new ThreadExecutor(Looper.getMainLooper());
/**
* The worker thread.
*
* @return a non-null executor.
*/
@NonNull
public static Executor worker() {
return sWorker;
}
/**
* The main thread.
*
* @return a non-null executor that does work on the main thread.
*/
@NonNull
public static Executor main() {
return sMain;

20
app/src/main/java/acr/browser/lightning/react/Subscriber.java

@ -1,7 +1,25 @@ @@ -1,7 +1,25 @@
package acr.browser.lightning.react;
import android.support.annotation.Nullable;
public interface Subscriber<T> {
void onNext(T item);
/**
* Called when the Observer emits an
* item. It can be called multiple times.
* It cannot be called after onComplete
* has been called.
*
* @param item the item that has been emitted,
* can be null.
*/
void onNext(@Nullable T item);
/**
* This method is called when the observer is
* finished sending the subscriber events. It
* is guaranteed that no other methods will be
* called on the Subscription after this method
* has been called.
*/
void onComplete();
}

21
app/src/main/java/acr/browser/lightning/react/Subscription.java

@ -1,7 +1,26 @@ @@ -1,7 +1,26 @@
package acr.browser.lightning.react;
import android.support.annotation.Nullable;
public interface Subscription<T> {
void onNext(T item);
/**
* Called when the Observer emits an
* item. It can be called multiple times.
* It cannot be called after onComplete
* has been called.
*
* @param item the item that has been emitted,
* can be null.
*/
void onNext(@Nullable T item);
/**
* This method is called when the observer is
* finished sending the subscriber events. It
* is guaranteed that no other methods will be
* called on the Subscription after this method
* has been called.
*/
void onComplete();
}

2
app/src/main/java/acr/browser/lightning/view/LightningView.java

@ -417,7 +417,7 @@ public class LightningView { @@ -417,7 +417,7 @@ public class LightningView {
private Observable<File> getPathObservable(final String subFolder) {
return Observable.create(new Action<File>() {
@Override
public void onSubscribe(Subscriber<File> subscriber) {
public void onSubscribe(@NonNull Subscriber<File> subscriber) {
File file = BrowserApp.get(mActivity).getDir(subFolder, 0);
subscriber.onNext(file);
subscriber.onComplete();

Loading…
Cancel
Save