Created AsyncDatabaseChangeHandler

This commit is contained in:
Phillip Hsu 2016-07-30 19:01:29 -07:00
parent 066ac67325
commit 7b0a32938e
5 changed files with 161 additions and 104 deletions

View File

@ -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<T>> {
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<Void, Void, Integer>() {
@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<Void, Void, Long> {
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);
}
}
}

View File

@ -1,25 +1,23 @@
package com.philliphsu.clock2; package com.philliphsu.clock2;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.view.View; import android.view.View;
import com.philliphsu.clock2.alarms.ScrollHandler; import com.philliphsu.clock2.alarms.ScrollHandler;
import com.philliphsu.clock2.model.DatabaseManager; import com.philliphsu.clock2.model.AlarmsTableManager;
import com.philliphsu.clock2.util.AlarmController; import com.philliphsu.clock2.util.AlarmController;
/** /**
* Created by Phillip Hsu on 7/1/2016. * 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<Alarm, AlarmsTableManager> {
private static final String TAG = "AsyncItemChangeHandler"; private static final String TAG = "AsyncItemChangeHandler";
private final Context mContext;
private final View mSnackbarAnchor; private final View mSnackbarAnchor;
private final ScrollHandler mScrollHandler;
private final AlarmController mAlarmController; private final AlarmController mAlarmController;
/** /**
@ -29,108 +27,41 @@ public final class AsyncItemChangeHandler {
public AsyncItemChangeHandler(Context context, View snackbarAnchor, public AsyncItemChangeHandler(Context context, View snackbarAnchor,
ScrollHandler scrollHandler, ScrollHandler scrollHandler,
AlarmController alarmController) { AlarmController alarmController) {
mContext = context.getApplicationContext(); // to prevent memory leaks super(context, scrollHandler);
mSnackbarAnchor = snackbarAnchor; mSnackbarAnchor = snackbarAnchor;
mScrollHandler = scrollHandler;
mAlarmController = alarmController; mAlarmController = alarmController;
} }
public void asyncAddAlarm(final Alarm alarm) {
new InsertAlarmAsyncTask(alarm).execute();
}
/**
* 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<Void, Void, Integer>() {
@Override @Override
protected Integer doInBackground(Void... params) { protected AlarmsTableManager getTableManager(Context context) {
return DatabaseManager.getInstance(mContext).deleteAlarm(alarm); return new AlarmsTableManager(context);
} }
@Override @Override
protected void onPostExecute(Integer integer) { protected void onPostAsyncDelete(Integer result, final Alarm alarm) {
mAlarmController.cancelAlarm(alarm, false); mAlarmController.cancelAlarm(alarm, false);
if (mSnackbarAnchor != null) { if (mSnackbarAnchor != null) {
// TODO: Consider adding delay to allow the alarm item animation // TODO: Consider adding delay to allow the alarm item animation
// to finish first before we show the snackbar. Inbox app does this. // to finish first before we show the snackbar. Inbox app does this.
String message = mContext.getString(R.string.snackbar_item_deleted, String message = getContext().getString(R.string.snackbar_item_deleted,
mContext.getString(R.string.alarm)); getContext().getString(R.string.alarm));
Snackbar.make(mSnackbarAnchor, message, Snackbar.LENGTH_LONG) Snackbar.make(mSnackbarAnchor, message, Snackbar.LENGTH_LONG)
.setAction(R.string.snackbar_undo_item_deleted, new View.OnClickListener() { .setAction(R.string.snackbar_undo_item_deleted, new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
asyncAddAlarm(alarm); asyncInsert(alarm);
} }
}).show(); }).show();
} }
} }
}.execute();
}
//////////////////////////////////////////////////////////// @Override
// Insert and update AsyncTasks protected void onPostAsyncInsert(Long result, Alarm alarm) {
//////////////////////////////////////////////////////////// mAlarmController.scheduleAlarm(alarm, true);
/**
* Created because the code in insert and update AsyncTasks are exactly the same.
*/
private abstract class BaseAsyncTask extends AsyncTask<Void, Void, Long> {
private final Alarm mAlarm;
BaseAsyncTask(Alarm alarm) {
mAlarm = alarm;
} }
@Override @Override
protected void onPostExecute(Long result) { protected void onPostAsyncUpdate(Long result, Alarm alarm) {
// TODO: Consider adding delay to allow the alarm item animation mAlarmController.scheduleAlarm(alarm, true);
// 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;
}
}
private class InsertAlarmAsyncTask extends BaseAsyncTask {
InsertAlarmAsyncTask(Alarm alarm) {
super(alarm);
}
@Override
protected Long doInBackground(Void... params) {
return insertAlarm();
}
}
private class UpdateAlarmAsyncTask extends BaseAsyncTask {
UpdateAlarmAsyncTask(Alarm alarm) {
super(alarm);
}
@Override
protected Long doInBackground(Void... params) {
return updateAlarm();
}
} }
} }

View File

@ -18,7 +18,8 @@ import butterknife.Bind;
/** /**
* Created by Phillip Hsu on 7/26/2016. * Created by Phillip Hsu on 7/26/2016.
*/ */
public abstract class RecyclerViewFragment<T extends ObjectWithId, public abstract class RecyclerViewFragment<
T extends ObjectWithId,
VH extends BaseViewHolder<T>, VH extends BaseViewHolder<T>,
C extends BaseItemCursor<T>, C extends BaseItemCursor<T>,
A extends BaseCursorAdapter<T, VH, C>> A extends BaseCursorAdapter<T, VH, C>>

View File

@ -138,7 +138,7 @@ public class AlarmsFragment extends RecyclerViewFragment<
if (data.getBooleanExtra(EditAlarmActivity.EXTRA_IS_DELETING, false)) { if (data.getBooleanExtra(EditAlarmActivity.EXTRA_IS_DELETING, false)) {
// TODO: Should we delay this too? It seems animations run // TODO: Should we delay this too? It seems animations run
// some of the time. // some of the time.
mAsyncItemChangeHandler.asyncRemoveAlarm(alarm); mAsyncItemChangeHandler.asyncDelete(alarm);
} else { } else {
// TODO: Increase the delay, because update animation is // TODO: Increase the delay, because update animation is
// more elusive than insert. // more elusive than insert.
@ -206,15 +206,15 @@ public class AlarmsFragment extends RecyclerViewFragment<
} }
void asyncAddAlarm() { void asyncAddAlarm() {
mAsyncItemChangeHandler.asyncAddAlarm(mAlarm); mAsyncItemChangeHandler.asyncInsert(mAlarm);
} }
void asyncUpdateAlarm() { void asyncUpdateAlarm() {
mAsyncItemChangeHandler.asyncUpdateAlarm(mAlarm); mAsyncItemChangeHandler.asyncUpdate(mAlarm.getId(), mAlarm);
} }
void asyncRemoveAlarm() { void asyncRemoveAlarm() {
mAsyncItemChangeHandler.asyncRemoveAlarm(mAlarm); mAsyncItemChangeHandler.asyncDelete(mAlarm);
} }
} }

View File

@ -9,7 +9,6 @@ import com.philliphsu.clock2.RecyclerViewFragment;
import com.philliphsu.clock2.Timer; import com.philliphsu.clock2.Timer;
import com.philliphsu.clock2.edittimer.EditTimerActivity; import com.philliphsu.clock2.edittimer.EditTimerActivity;
import com.philliphsu.clock2.model.TimerCursor; import com.philliphsu.clock2.model.TimerCursor;
import com.philliphsu.clock2.model.TimerDatabaseHelper;
import com.philliphsu.clock2.model.TimersListCursorLoader; import com.philliphsu.clock2.model.TimersListCursorLoader;
public class TimersFragment extends RecyclerViewFragment< public class TimersFragment extends RecyclerViewFragment<
@ -23,8 +22,6 @@ public class TimersFragment extends RecyclerViewFragment<
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
// if (resultCode != Activity.RESULT_OK || data == null) // if (resultCode != Activity.RESULT_OK || data == null)
// return; // return;
TimerDatabaseHelper db = new TimerDatabaseHelper(getActivity());
db.insertItem(Timer.create(1, 0, 0));
} }
@Override @Override