Fix crash(es) caused by failing to dispose Rx observables (#2669)

This commit is contained in:
Dmitry Brant 2019-03-19 17:08:04 -04:00 committed by Adam Jones
parent 38d39e08ac
commit 8474c04c64
21 changed files with 121 additions and 86 deletions

View file

@ -17,6 +17,7 @@ import androidx.exifinterface.media.ExifInterface;
import fr.free.nrw.commons.caching.CacheController;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.mwapi.CategoryApi;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
@ -42,11 +43,16 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
private ExifInterface exifInterface;
private boolean haveCheckedForOtherImages = false;
private GPSExtractor tempImageObj;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
@Inject
FileProcessor() {
}
public void cleanup() {
compositeDisposable.clear();
}
void initFileDetails(@NonNull String filePath, ContentResolver contentResolver) {
this.filePath = filePath;
this.contentResolver = contentResolver;
@ -138,7 +144,7 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
// If no categories found in cache, call MediaWiki API to match image coords with nearby Commons categories
if (catListEmpty) {
apiCall.request(decimalCoords)
compositeDisposable.add(apiCall.request(decimalCoords)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(
@ -147,7 +153,7 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
Timber.e(throwable);
gpsCategoryModel.clear();
}
);
));
Timber.d("displayCatList size 0, calling MWAPI %s", displayCatList);
} else {
Timber.d("Cache found, setting categoryList in model to %s", displayCatList);

View file

@ -33,16 +33,19 @@ public class ImageProcessingService {
private final MediaWikiApi mwApi;
private final ReadFBMD readFBMD;
private final EXIFReader EXIFReader;
private final Context context;
@Inject
public ImageProcessingService(FileUtilsWrapper fileUtilsWrapper,
ImageUtilsWrapper imageUtilsWrapper,
MediaWikiApi mwApi, ReadFBMD readFBMD, EXIFReader EXIFReader) {
MediaWikiApi mwApi, ReadFBMD readFBMD, EXIFReader EXIFReader,
Context context) {
this.fileUtilsWrapper = fileUtilsWrapper;
this.imageUtilsWrapper = imageUtilsWrapper;
this.mwApi = mwApi;
this.readFBMD = readFBMD;
this.EXIFReader = EXIFReader;
this.context = context;
}
/**
@ -61,13 +64,13 @@ public class ImageProcessingService {
Timber.d("Checking the validity of image");
String filePath = uploadItem.getMediaUri().getPath();
Uri contentUri=uploadItem.getContentUri();
Context context=uploadItem.getContext();
Single<Integer> duplicateImage = checkDuplicateImage(filePath);
Single<Integer> wrongGeoLocation = checkImageGeoLocation(uploadItem.getPlace(), filePath);
Single<Integer> darkImage = checkDarkImage(filePath);
Single<Integer> itemTitle = checkTitle ? validateItemTitle(uploadItem) : Single.just(ImageUtils.IMAGE_OK);
Single<Integer> checkFBMD = checkFBMD(context,contentUri);
Single<Integer> checkEXIF = checkEXIF(filePath);
Single<Integer> zipResult = Single.zip(duplicateImage, wrongGeoLocation, darkImage, itemTitle,
(duplicate, wrongGeo, dark, title) -> {
Timber.d("Result for duplicate: %d, geo: %d, dark: %d, title: %d", duplicate, wrongGeo, dark, title);

View file

@ -5,7 +5,6 @@ import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.textfield.TextInputLayout;
import androidx.appcompat.app.AlertDialog;
@ -67,7 +66,6 @@ import fr.free.nrw.commons.utils.PermissionUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
@ -134,7 +132,6 @@ public class UploadActivity extends BaseActivity implements UploadView, SimilarI
private DescriptionsAdapter descriptionsAdapter;
private RVRendererAdapter<CategoryItem> categoriesAdapter;
private CompositeDisposable compositeDisposable;
private ProgressDialog progressDialog;
@ -145,7 +142,6 @@ public class UploadActivity extends BaseActivity implements UploadView, SimilarI
setContentView(R.layout.activity_upload);
ButterKnife.bind(this);
compositeDisposable = new CompositeDisposable();
configureLayout();
configureTopCard();
@ -211,8 +207,6 @@ public class UploadActivity extends BaseActivity implements UploadView, SimilarI
@Override
protected void onPause() {
presenter.removeView();
compositeDisposable.dispose();
compositeDisposable = new CompositeDisposable();
super.onPause();
}
@ -571,7 +565,7 @@ public class UploadActivity extends BaseActivity implements UploadView, SimilarI
@SuppressLint("CheckResult")
private void updateCategoryList(String filter) {
List<String> imageTitleList = presenter.getImageTitleList();
Observable.fromIterable(categoriesModel.getSelectedCategories())
compositeDisposable.add(Observable.fromIterable(categoriesModel.getSelectedCategories())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(disposable -> {
@ -602,7 +596,7 @@ public class UploadActivity extends BaseActivity implements UploadView, SimilarI
categoriesSearchContainer.setError("No categories found");
}
}
);
));
}
private void receiveSharedItems() {

View file

@ -26,7 +26,7 @@ import fr.free.nrw.commons.utils.ImageUtils;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
@ -45,6 +45,7 @@ public class UploadModel {
};
private final JsonKvStore store;
private final List<String> licenses;
private final Context context;
private String license;
private final Map<String, String> licensesByName;
private List<UploadItem> items = new ArrayList<>();
@ -52,8 +53,7 @@ public class UploadModel {
private boolean bottomCardState = true;
private boolean rightCardState = true;
private int currentStepIndex = 0;
public static Context context;
private Disposable badImageSubscription;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private SessionManager sessionManager;
private FileProcessor fileProcessor;
@ -77,6 +77,11 @@ public class UploadModel {
this.imageProcessingService = imageProcessingService;
}
void cleanup() {
compositeDisposable.clear();
fileProcessor.cleanup();
}
@SuppressLint("CheckResult")
Observable<UploadItem> preProcessImages(List<UploadableFile> uploadableFiles,
Place place,
@ -219,8 +224,7 @@ public class UploadModel {
}
public void previous() {
if (badImageSubscription != null)
badImageSubscription.dispose();
cleanup();
markCurrentUploadVisited();
if (currentStepIndex > 0) {
currentStepIndex--;
@ -305,16 +309,16 @@ public class UploadModel {
}
void deletePicture() {
badImageSubscription.dispose();
cleanup();
updateItemState();
}
void subscribeBadPicture(Consumer<Integer> consumer, boolean checkTitle) {
if (isShowingItem()) {
badImageSubscription = getImageQuality(getCurrentItem(), checkTitle)
compositeDisposable.add(getImageQuality(getCurrentItem(), checkTitle)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(consumer, Timber::e);
.subscribe(consumer, Timber::e));
}
}
@ -432,10 +436,6 @@ public class UploadModel {
public Uri getContentUri() {
return originalContentUri;
}
public Context getContext(){
return UploadModel.context;
}
}
}

View file

@ -21,6 +21,7 @@ import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.utils.StringUtils;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
@ -52,6 +53,7 @@ public class UploadPresenter {
private final UploadController uploadController;
private final Context context;
private final JsonKvStore directKvStore;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
@Inject
UploadPresenter(UploadModel uploadModel,
@ -77,12 +79,12 @@ public class UploadPresenter {
Observable<UploadItem> uploadItemObservable = uploadModel
.preProcessImages(media, place, source, similarImageInterface);
uploadItemObservable
compositeDisposable.add(uploadItemObservable
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(uploadItems -> onImagesProcessed(uploadItems, place),
throwable -> Timber.e(throwable, "Error occurred in processing images"));
throwable -> Timber.e(throwable, "Error occurred in processing images")));
}
private void onImagesProcessed(List<UploadItem> uploadItems, Place place) {
@ -211,9 +213,9 @@ public class UploadPresenter {
@SuppressLint("CheckResult")
void handleSubmit(CategoriesModel categoriesModel) {
if (view.checkIfLoggedIn())
uploadModel.buildContributions(categoriesModel.getCategoryStringList())
compositeDisposable.add(uploadModel.buildContributions(categoriesModel.getCategoryStringList())
.observeOn(Schedulers.io())
.subscribe(uploadController::startUpload);
.subscribe(uploadController::startUpload));
}
/**
@ -286,6 +288,8 @@ public class UploadPresenter {
}
void cleanup() {
compositeDisposable.clear();
uploadModel.cleanup();
uploadController.cleanup();
}