diff --git a/AnkiDroid/build.gradle b/AnkiDroid/build.gradle index 20428df92467..b6cb7c8686be 100644 --- a/AnkiDroid/build.gradle +++ b/AnkiDroid/build.gradle @@ -108,11 +108,12 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'crea dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:27.0.2' + def support_lib_version = '27.1.1' + implementation "com.android.support:appcompat-v7:$support_lib_version" // Note: the design support library can be quite buggy, so test everything thoroughly before updating it - implementation 'com.android.support:design:27.0.2' - implementation 'com.android.support:customtabs:27.0.2' - implementation 'com.android.support:recyclerview-v7:27.0.2' + implementation "com.android.support:design:$support_lib_version" + implementation "com.android.support:customtabs:$support_lib_version" + implementation "com.android.support:recyclerview-v7:$support_lib_version" implementation 'io.requery:sqlite-android:3.24.0' implementation 'android.arch.persistence:db:1.1.1' implementation 'com.afollestad.material-dialogs:core:0.9.6.0' diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.java b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.java index 2b50835c51b8..ef775a4bc5f0 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.java @@ -15,10 +15,8 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; -import android.support.v4.app.LoaderManager; import android.support.v4.app.NotificationCompat; import android.support.v4.content.ContextCompat; -import android.support.v4.content.Loader; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; @@ -38,8 +36,7 @@ import timber.log.Timber; -public class AnkiActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks, - SimpleMessageDialog.SimpleMessageDialogListener { +public class AnkiActivity extends AppCompatActivity implements SimpleMessageDialog.SimpleMessageDialogListener { public final int SIMPLE_NOTIFICATION_ID = 0; public static final int REQUEST_REVIEW = 901; @@ -97,6 +94,7 @@ public boolean onOptionsItemSelected(MenuItem item) { // called when the CollectionLoader finishes... usually will be over-ridden protected void onCollectionLoaded(Collection col) { + hideProgressBar(); } @@ -250,49 +248,25 @@ private void enableActivityAnimation(int animation) { // Method for loading the collection which is inherited by all AnkiActivitys public void startLoadingCollection() { - // Initialize the open collection loader Timber.d("AnkiActivity.startLoadingCollection()"); - if (!colIsOpen()) { - showProgressBar(); + if (colIsOpen()) { + onCollectionLoaded(getCol()); + return; } - getSupportLoaderManager().restartLoader(0, null, this); - } - - - // Kick user back to DeckPicker on collection load error unless this method is overridden - protected void onCollectionLoadError() { - Intent deckPicker = new Intent(this, DeckPicker.class); - deckPicker.putExtra("collectionLoadError", true); // don't currently do anything with this - deckPicker.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); - startActivityWithAnimation(deckPicker, ActivityTransitionAnimation.LEFT); - } - - - // CollectionLoader Listener callbacks - @Override - public Loader onCreateLoader(int id, Bundle args) { - // Currently only using one loader, so ignore id - return new CollectionLoader(this); - } - - - @Override - public void onLoadFinished(Loader loader, Collection col) { - hideProgressBar(); - if (col != null && colIsOpen()) { - onCollectionLoaded(col); - } else { - onCollectionLoadError(); - } - } - - - @Override - public void onLoaderReset(Loader arg0) { - // We don't currently retain any references, so no need to free any data here + // Open collection asynchronously if it hasn't already been opened + showProgressBar(); + CollectionLoader.load(this, col -> { + if (col != null) { + onCollectionLoaded(col); + } else { + Intent deckPicker = new Intent(this, DeckPicker.class); + deckPicker.putExtra("collectionLoadError", true); // don't currently do anything with this + deckPicker.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivityWithAnimation(deckPicker, ActivityTransitionAnimation.LEFT); + } + }); } - public void showProgressBar() { ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar); if (progressBar != null) { diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java index 264d65f47ec5..737a5488f9d1 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java @@ -823,7 +823,7 @@ private void onFinishedStartup() { getCol().modSchema(); } catch (ConfirmModSchemaException e) { // If libanki determines it's necessary to confirm the full sync then show a confirmation dialog - // We have to show the dialog via the DialogHandler since this method is called via a Loader + // We have to show the dialog via the DialogHandler since this method is called via an async task Resources res = getResources(); Message handlerMessage = Message.obtain(); handlerMessage.what = DialogHandler.MSG_SHOW_FORCE_FULL_SYNC_DIALOG; @@ -841,12 +841,10 @@ private void onFinishedStartup() { automaticSync(); } - @Override - protected void onCollectionLoadError() { + private void showCollectionErrorDialog() { getDialogHandler().sendEmptyMessage(DialogHandler.MSG_SHOW_COLLECTION_LOADING_ERROR_DIALOG); } - public void addNote() { Intent intent = new Intent(DeckPicker.this, NoteEditor.class); intent.putExtra(NoteEditor.EXTRA_CALLER, NoteEditor.CALLER_DECKPICKER); @@ -1144,7 +1142,7 @@ public void onPostExecute(DeckTask.TaskData result) { } if (result == null || !result.getBoolean()) { UIUtils.showThemedToast(DeckPicker.this, getResources().getString(R.string.deck_repair_error), true); - onCollectionLoadError(); + showCollectionErrorDialog(); } } @@ -1871,7 +1869,7 @@ public void onPostExecute(TaskData result) { } if (result == null) { Timber.e("null result loading deck counts"); - onCollectionLoadError(); + showCollectionErrorDialog(); return; } List nodes = (List) result.getObjArray()[0]; diff --git a/AnkiDroid/src/main/java/com/ichi2/async/CollectionLoader.java b/AnkiDroid/src/main/java/com/ichi2/async/CollectionLoader.java index 03e30d8cb185..e9b1c95e2c57 100644 --- a/AnkiDroid/src/main/java/com/ichi2/async/CollectionLoader.java +++ b/AnkiDroid/src/main/java/com/ichi2/async/CollectionLoader.java @@ -1,7 +1,8 @@ package com.ichi2.async; -import android.content.Context; -import android.support.v4.content.AsyncTaskLoader; +import android.arch.lifecycle.Lifecycle; +import android.arch.lifecycle.LifecycleOwner; +import android.os.AsyncTask; import com.ichi2.anki.AnkiDroidApp; import com.ichi2.anki.CollectionHelper; @@ -9,62 +10,48 @@ import timber.log.Timber; -public class CollectionLoader extends AsyncTaskLoader { +public final class CollectionLoader extends AsyncTask { + private LifecycleOwner mLifecycleOwner; + private Callback mCallback; - public CollectionLoader(Context context) { - super(context); + public interface Callback { + void execute(Collection col); + } + + public static void load(LifecycleOwner lifecycleOwner, Callback callback) { + CollectionLoader loader = new CollectionLoader(lifecycleOwner, callback); + loader.execute(); + } + + private CollectionLoader(LifecycleOwner lifecycleOwner, Callback callback) { + mLifecycleOwner = lifecycleOwner; + mCallback = callback; } @Override - public Collection loadInBackground() { + protected Collection doInBackground(Void... params) { + // Don't touch collection if lockCollection flag is set + if (CollectionHelper.getInstance().isCollectionLocked()) { + Timber.w("onStartLoading() :: Another thread has requested to keep the collection closed."); + return null; + } // load collection try { Timber.d("CollectionLoader accessing collection"); - return CollectionHelper.getInstance().getCol(getContext()); + return CollectionHelper.getInstance().getCol(AnkiDroidApp.getInstance().getApplicationContext()); } catch (RuntimeException e) { Timber.e(e, "loadInBackground - RuntimeException on opening collection"); AnkiDroidApp.sendExceptionReport(e, "CollectionLoader.loadInBackground"); return null; } } - - @Override - public void deliverResult(Collection col) { - Timber.d("CollectionLoader.deliverResult()"); - // Loader has been reset so don't forward data to listener - if (isReset()) { - if (col != null) { - return; - } - } - // Loader is running so forward data to listener - if (isStarted()) { - super.deliverResult(col); - } - } - + @Override - protected void onStartLoading() { - // Don't touch collection if lockCollection flag is set - if (CollectionHelper.getInstance().isCollectionLocked()) { - Timber.w("onStartLoading() :: Another thread has requested to keep the collection closed."); - return; + protected void onPostExecute(Collection col) { + super.onPostExecute(col); + if (mLifecycleOwner.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.CREATED)) { + mCallback.execute(col); } - // Since the CollectionHelper only opens if necessary, we can just force every time - forceLoad(); - } - - @Override - protected void onStopLoading() { - // The Loader has been put in a stopped state, so we should attempt to cancel the current load (if there is one). - Timber.d("CollectionLoader.onStopLoading()"); - cancelLoad(); - } - - @Override - protected void onReset() { - // Ensure the loader is stopped. - Timber.d("CollectionLoader.onReset()"); - onStopLoading(); } + } \ No newline at end of file