From 7b0a32938efa0949187998fec064ff2a16e61aa2 Mon Sep 17 00:00:00 2001 From: Phillip Hsu Date: Sat, 30 Jul 2016 19:01:29 -0700 Subject: [PATCH] Created AsyncDatabaseChangeHandler --- .../clock2/AsyncDatabaseChangeHandler.java | 128 ++++++++++++++++++ .../clock2/AsyncItemChangeHandler.java | 123 ++++------------- .../clock2/RecyclerViewFragment.java | 3 +- .../clock2/alarms/AlarmsFragment.java | 8 +- .../clock2/timers/TimersFragment.java | 3 - 5 files changed, 161 insertions(+), 104 deletions(-) create mode 100644 app/src/main/java/com/philliphsu/clock2/AsyncDatabaseChangeHandler.java diff --git a/app/src/main/java/com/philliphsu/clock2/AsyncDatabaseChangeHandler.java b/app/src/main/java/com/philliphsu/clock2/AsyncDatabaseChangeHandler.java new file mode 100644 index 0000000..8e7b724 --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/AsyncDatabaseChangeHandler.java @@ -0,0 +1,128 @@ +package com.philliphsu.clock2; + +import android.content.Context; +import android.os.AsyncTask; + +import com.philliphsu.clock2.alarms.ScrollHandler; +import com.philliphsu.clock2.model.DatabaseTableManager; +import com.philliphsu.clock2.model.ObjectWithId; + +/** + * Created by Phillip Hsu on 7/1/2016. + */ +public abstract class AsyncDatabaseChangeHandler< + T extends ObjectWithId, + TM extends DatabaseTableManager> { + private static final String TAG = "AsyncDatabaseChangeHandler"; + + private final Context mAppContext; + private final ScrollHandler mScrollHandler; + private final TM mTableManager; + + /** + * @param context the Context from which we get the application context + */ + public AsyncDatabaseChangeHandler(Context context, ScrollHandler scrollHandler) { + mAppContext = context.getApplicationContext(); // to prevent memory leaks + mScrollHandler = scrollHandler; + mTableManager = getTableManager(context); + } + + public final void asyncInsert(final T item) { + new InsertAsyncTask(item).execute(); + } + + public final void asyncUpdate(final long id, final T newItem) { + new UpdateAsyncTask(id, newItem).execute(); + } + + public final void asyncDelete(final T item) { + // TODO: If we want to scroll somewhere after we delete this item, we can + // create a DeleteAsyncTask subclass of the BaseAsyncTask. This involves + // using a Long result, however. + new AsyncTask() { + @Override + protected Integer doInBackground(Void... params) { + return mTableManager.deleteItem(item); + } + + @Override + protected void onPostExecute(Integer integer) { + onPostAsyncDelete(integer, item); + } + }.execute(); + } + + protected final Context getContext() { + return mAppContext; + } + + protected abstract TM getTableManager(Context context); + + protected abstract void onPostAsyncDelete(Integer result, T item); + + protected abstract void onPostAsyncInsert(Long result, T item); + + protected abstract void onPostAsyncUpdate(Long result, T item); + + //////////////////////////////////////////////////////////// + // Insert and update AsyncTasks + //////////////////////////////////////////////////////////// + + /** + * Created because the code in insert and update AsyncTasks are exactly the same. + */ + private abstract class BaseAsyncTask extends AsyncTask { + final T mItem; + + BaseAsyncTask(T item) { + mItem = item; + } + + @Override + protected void onPostExecute(Long result) { + if (mScrollHandler != null) { + // Prepare to scroll to this alarm + mScrollHandler.setScrollToStableId(result); + } + } + } + + private class InsertAsyncTask extends BaseAsyncTask { + InsertAsyncTask(T item) { + super(item); + } + + @Override + protected Long doInBackground(Void... params) { + return mTableManager.insertItem(mItem); + } + + @Override + protected void onPostExecute(Long result) { + super.onPostExecute(result); + onPostAsyncInsert(result, mItem); + } + } + + private class UpdateAsyncTask extends BaseAsyncTask { + private final long mId; + + UpdateAsyncTask(long id, T item) { + super(item); + mId = id; + } + + @Override + protected Long doInBackground(Void... params) { + mTableManager.updateItem(mId, mItem); + return mId; + } + + @Override + protected void onPostExecute(Long result) { + super.onPostExecute(result); + onPostAsyncUpdate(result, mItem); + } + } +} diff --git a/app/src/main/java/com/philliphsu/clock2/AsyncItemChangeHandler.java b/app/src/main/java/com/philliphsu/clock2/AsyncItemChangeHandler.java index 35e2403..a88d9cf 100644 --- a/app/src/main/java/com/philliphsu/clock2/AsyncItemChangeHandler.java +++ b/app/src/main/java/com/philliphsu/clock2/AsyncItemChangeHandler.java @@ -1,25 +1,23 @@ package com.philliphsu.clock2; import android.content.Context; -import android.os.AsyncTask; import android.support.design.widget.Snackbar; import android.view.View; import com.philliphsu.clock2.alarms.ScrollHandler; -import com.philliphsu.clock2.model.DatabaseManager; +import com.philliphsu.clock2.model.AlarmsTableManager; import com.philliphsu.clock2.util.AlarmController; /** * Created by Phillip Hsu on 7/1/2016. * - * TODO: Generify this class for any item. + * TODO: Rename to AsyncAlarmChangeHandler + * TODO: Consider making an AsyncDatabaseChangeHandlerWithSnackbar abstract class */ -public final class AsyncItemChangeHandler { +public final class AsyncItemChangeHandler extends AsyncDatabaseChangeHandler { private static final String TAG = "AsyncItemChangeHandler"; - private final Context mContext; private final View mSnackbarAnchor; - private final ScrollHandler mScrollHandler; private final AlarmController mAlarmController; /** @@ -29,108 +27,41 @@ public final class AsyncItemChangeHandler { public AsyncItemChangeHandler(Context context, View snackbarAnchor, ScrollHandler scrollHandler, AlarmController alarmController) { - mContext = context.getApplicationContext(); // to prevent memory leaks + super(context, scrollHandler); mSnackbarAnchor = snackbarAnchor; - mScrollHandler = scrollHandler; mAlarmController = alarmController; } - public void asyncAddAlarm(final Alarm alarm) { - new InsertAlarmAsyncTask(alarm).execute(); + @Override + protected AlarmsTableManager getTableManager(Context context) { + return new AlarmsTableManager(context); } - /** - * We only need one Alarm param because we called newAlarm.setId(oldAlarm.id()) - * when we were in the edit activity. - * TODO: Consider changing the signature of updateAlarm() in DatabaseManager and - * AlarmDatabaseHelper to only require one Alarm param. - */ - public void asyncUpdateAlarm(final Alarm newAlarm) { - new UpdateAlarmAsyncTask(newAlarm).execute(); - } - - public void asyncRemoveAlarm(final Alarm alarm) { - new AsyncTask() { - @Override - protected Integer doInBackground(Void... params) { - return DatabaseManager.getInstance(mContext).deleteAlarm(alarm); - } - - @Override - protected void onPostExecute(Integer integer) { - mAlarmController.cancelAlarm(alarm, false); - if (mSnackbarAnchor != null) { - // TODO: Consider adding delay to allow the alarm item animation - // to finish first before we show the snackbar. Inbox app does this. - String message = mContext.getString(R.string.snackbar_item_deleted, - mContext.getString(R.string.alarm)); - Snackbar.make(mSnackbarAnchor, message, Snackbar.LENGTH_LONG) - .setAction(R.string.snackbar_undo_item_deleted, new View.OnClickListener() { - @Override - public void onClick(View v) { - asyncAddAlarm(alarm); - } - }).show(); - } - } - }.execute(); - } - - //////////////////////////////////////////////////////////// - // Insert and update AsyncTasks - //////////////////////////////////////////////////////////// - - /** - * Created because the code in insert and update AsyncTasks are exactly the same. - */ - private abstract class BaseAsyncTask extends AsyncTask { - private final Alarm mAlarm; - - BaseAsyncTask(Alarm alarm) { - mAlarm = alarm; - } - - @Override - protected void onPostExecute(Long result) { + @Override + protected void onPostAsyncDelete(Integer result, final Alarm alarm) { + mAlarmController.cancelAlarm(alarm, false); + if (mSnackbarAnchor != null) { // TODO: Consider adding delay to allow the alarm item animation // to finish first before we show the snackbar. Inbox app does this. - mAlarmController.scheduleAlarm(mAlarm, true); - if (mScrollHandler != null) { - // Prepare to scroll to this alarm - mScrollHandler.setScrollToStableId(result); - } - } - - final Long insertAlarm() { - return DatabaseManager.getInstance(mContext).insertAlarm(mAlarm); - } - - final Long updateAlarm() { - long id = mAlarm.id(); - DatabaseManager.getInstance(mContext).updateAlarm(id, mAlarm); - return id; + String message = getContext().getString(R.string.snackbar_item_deleted, + getContext().getString(R.string.alarm)); + Snackbar.make(mSnackbarAnchor, message, Snackbar.LENGTH_LONG) + .setAction(R.string.snackbar_undo_item_deleted, new View.OnClickListener() { + @Override + public void onClick(View v) { + asyncInsert(alarm); + } + }).show(); } } - private class InsertAlarmAsyncTask extends BaseAsyncTask { - InsertAlarmAsyncTask(Alarm alarm) { - super(alarm); - } - - @Override - protected Long doInBackground(Void... params) { - return insertAlarm(); - } + @Override + protected void onPostAsyncInsert(Long result, Alarm alarm) { + mAlarmController.scheduleAlarm(alarm, true); } - private class UpdateAlarmAsyncTask extends BaseAsyncTask { - UpdateAlarmAsyncTask(Alarm alarm) { - super(alarm); - } - - @Override - protected Long doInBackground(Void... params) { - return updateAlarm(); - } + @Override + protected void onPostAsyncUpdate(Long result, Alarm alarm) { + mAlarmController.scheduleAlarm(alarm, true); } } diff --git a/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java b/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java index 264d630..7f684e1 100644 --- a/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java +++ b/app/src/main/java/com/philliphsu/clock2/RecyclerViewFragment.java @@ -18,7 +18,8 @@ import butterknife.Bind; /** * Created by Phillip Hsu on 7/26/2016. */ -public abstract class RecyclerViewFragment, C extends BaseItemCursor, A extends BaseCursorAdapter> diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java index 3b41e6d..959edbb 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/AlarmsFragment.java @@ -138,7 +138,7 @@ public class AlarmsFragment extends RecyclerViewFragment< if (data.getBooleanExtra(EditAlarmActivity.EXTRA_IS_DELETING, false)) { // TODO: Should we delay this too? It seems animations run // some of the time. - mAsyncItemChangeHandler.asyncRemoveAlarm(alarm); + mAsyncItemChangeHandler.asyncDelete(alarm); } else { // TODO: Increase the delay, because update animation is // more elusive than insert. @@ -206,15 +206,15 @@ public class AlarmsFragment extends RecyclerViewFragment< } void asyncAddAlarm() { - mAsyncItemChangeHandler.asyncAddAlarm(mAlarm); + mAsyncItemChangeHandler.asyncInsert(mAlarm); } void asyncUpdateAlarm() { - mAsyncItemChangeHandler.asyncUpdateAlarm(mAlarm); + mAsyncItemChangeHandler.asyncUpdate(mAlarm.getId(), mAlarm); } void asyncRemoveAlarm() { - mAsyncItemChangeHandler.asyncRemoveAlarm(mAlarm); + mAsyncItemChangeHandler.asyncDelete(mAlarm); } } diff --git a/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java b/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java index 295deb6..21d20de 100644 --- a/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java +++ b/app/src/main/java/com/philliphsu/clock2/timers/TimersFragment.java @@ -9,7 +9,6 @@ import com.philliphsu.clock2.RecyclerViewFragment; import com.philliphsu.clock2.Timer; import com.philliphsu.clock2.edittimer.EditTimerActivity; import com.philliphsu.clock2.model.TimerCursor; -import com.philliphsu.clock2.model.TimerDatabaseHelper; import com.philliphsu.clock2.model.TimersListCursorLoader; public class TimersFragment extends RecyclerViewFragment< @@ -23,8 +22,6 @@ public class TimersFragment extends RecyclerViewFragment< public void onActivityResult(int requestCode, int resultCode, Intent data) { // if (resultCode != Activity.RESULT_OK || data == null) // return; - TimerDatabaseHelper db = new TimerDatabaseHelper(getActivity()); - db.insertItem(Timer.create(1, 0, 0)); } @Override