1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-11-14 22:17:11 +00:00

-Changed global Rx exception handling to no longer trigger error activity if the exception is undeliverable.

-Added debug settings to force reporting of undeliverable Rx exceptions.
-Changed back MediaSourceManager to use serial disposable for syncing.
This commit is contained in:
John Zhen Mo
2018-02-20 22:35:25 -08:00
parent cc7f27fb53
commit 1a92dfb019
6 changed files with 66 additions and 13 deletions

View File

@@ -30,9 +30,13 @@ import org.schabi.newpipe.util.StateSaver;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.util.Collections;
import java.util.List;
import io.reactivex.annotations.NonNull;
import io.reactivex.exceptions.CompositeException;
import io.reactivex.exceptions.MissingBackpressureException;
import io.reactivex.exceptions.OnErrorNotImplementedException;
import io.reactivex.exceptions.UndeliverableException;
import io.reactivex.functions.Consumer;
import io.reactivex.plugins.RxJavaPlugins;
@@ -99,31 +103,58 @@ public class App extends Application {
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : throwable = [" + throwable.getClass().getName() + "]");
Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : " +
"throwable = [" + throwable.getClass().getName() + "]");
if (throwable instanceof UndeliverableException) {
// As UndeliverableException is a wrapper, get the cause of it to get the "real" exception
throwable = throwable.getCause();
}
final List<Throwable> errors;
if (throwable instanceof CompositeException) {
for (Throwable element : ((CompositeException) throwable).getExceptions()) {
if (checkThrowable(element)) return;
errors = ((CompositeException) throwable).getExceptions();
} else {
errors = Collections.singletonList(throwable);
}
for (final Throwable error : errors) {
if (isThrowableIgnored(error)) return;
if (isThrowableCritical(error)) {
reportException(error);
return;
}
}
if (checkThrowable(throwable)) return;
// Out-of-lifecycle exceptions should only be reported if a debug user wishes so,
// When exception is not reported, log it
if (isDisposedRxExceptionsReported()) {
reportException(throwable);
} else {
Log.e(TAG, "RxJavaPlugin: Undeliverable Exception received: ", throwable);
}
}
private boolean isThrowableIgnored(@NonNull final Throwable throwable) {
// Don't crash the application over a simple network problem
return ExtractorHelper.hasAssignableCauseThrowable(throwable,
IOException.class, SocketException.class, // network api cancellation
InterruptedException.class, InterruptedIOException.class); // blocking code disposed
}
private boolean isThrowableCritical(@NonNull final Throwable throwable) {
// Though these exceptions cannot be ignored
return ExtractorHelper.hasAssignableCauseThrowable(throwable,
NullPointerException.class, IllegalArgumentException.class, // bug in app
OnErrorNotImplementedException.class, MissingBackpressureException.class,
IllegalStateException.class); // bug in operator
}
private void reportException(@NonNull final Throwable throwable) {
// Throw uncaught exception that will trigger the report system
Thread.currentThread().getUncaughtExceptionHandler()
.uncaughtException(Thread.currentThread(), throwable);
}
private boolean checkThrowable(@NonNull Throwable throwable) {
// Don't crash the application over a simple network problem
return ExtractorHelper.hasAssignableCauseThrowable(throwable,
IOException.class, SocketException.class, InterruptedException.class, InterruptedIOException.class);
}
});
}
@@ -177,4 +208,8 @@ public class App extends Application {
protected RefWatcher installLeakCanary() {
return RefWatcher.DISABLED;
}
protected boolean isDisposedRxExceptionsReported() {
return true;
}
}

View File

@@ -22,6 +22,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.disposables.SerialDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.subjects.PublishSubject;
@@ -45,7 +46,7 @@ public class MediaSourceManager {
private DynamicConcatenatingMediaSource sources;
private Subscription playQueueReactor;
private CompositeDisposable syncReactor;
private SerialDisposable syncReactor;
private PlayQueueItem syncedItem;
@@ -69,7 +70,7 @@ public class MediaSourceManager {
this.windowSize = windowSize;
this.loadDebounceMillis = loadDebounceMillis;
this.syncReactor = new CompositeDisposable();
this.syncReactor = new SerialDisposable();
this.debouncedLoadSignal = PublishSubject.create();
this.debouncedLoader = getDebouncedLoader();
@@ -251,7 +252,7 @@ public class MediaSourceManager {
final Disposable sync = currentItem.getStream()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onSuccess, onError);
syncReactor.add(sync);
syncReactor.set(sync);
}
}