Abstracted SQL, Cursor, Loader, Adapter, RecyclerView

This commit is contained in:
Phillip Hsu 2016-07-29 23:18:46 -07:00
parent 7c41ac2d29
commit b43ff03662
16 changed files with 654 additions and 71 deletions

View File

@ -79,7 +79,13 @@
android:exported="false"> android:exported="false">
</service> </service>
<activity android:name=".edittimer.EditTimerActivity"> <activity android:name=".edittimer.EditTimerActivity"
android:label="@string/title_activity_create_timer"
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="adjustNothing">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.philliphsu.clock2.MainActivity"/>
</activity> </activity>
</application> </application>

View File

@ -0,0 +1,78 @@
package com.philliphsu.clock2;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.ViewGroup;
import com.philliphsu.clock2.model.BaseItemCursor;
import com.philliphsu.clock2.model.ObjectWithId;
/**
* Created by Phillip Hsu on 7/29/2016.
*/
public abstract class BaseCursorAdapter<
T extends ObjectWithId,
VH extends BaseViewHolder<T>,
C extends BaseItemCursor<T>>
extends RecyclerView.Adapter<VH> {
private static final String TAG = "BaseCursorAdapter";
private final OnListItemInteractionListener<T> mListener;
private C mCursor;
protected abstract VH onCreateViewHolder(ViewGroup parent, OnListItemInteractionListener<T> listener);
public BaseCursorAdapter(OnListItemInteractionListener<T> listener) {
mListener = listener;
// Excerpt from docs of notifyDataSetChanged():
// "RecyclerView will attempt to synthesize [artificially create?]
// visible structural change events [when items are inserted, removed or
// moved] for adapters that report that they have stable IDs when
// [notifyDataSetChanged()] is used. This can help for the purposes of
// animation and visual object persistence [?] but individual item views
// will still need to be rebound and relaid out."
setHasStableIds(true);
}
/**
* not final to allow subclasses to use the viewType if needed
*/
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
return onCreateViewHolder(parent, mListener);
}
@Override
public final void onBindViewHolder(VH holder, int position) {
if (!mCursor.moveToPosition(position)) {
Log.e(TAG, "Failed to bind item at position " + position);
return;
}
holder.onBind(mCursor.getItem());
}
@Override
public final int getItemCount() {
return mCursor == null ? 0 : mCursor.getCount();
}
@Override
public final long getItemId(int position) {
if (mCursor == null || !mCursor.moveToPosition(position)) {
return super.getItemId(position); // -1
}
return mCursor.getId();
}
public final void swapCursor(C cursor) {
if (mCursor == cursor) {
return;
}
if (mCursor != null) {
mCursor.close();
}
mCursor = cursor;
notifyDataSetChanged();
}
}

View File

@ -15,7 +15,6 @@ import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import com.philliphsu.clock2.alarms.AlarmsFragment; import com.philliphsu.clock2.alarms.AlarmsFragment;
import com.philliphsu.clock2.editalarm.EditAlarmActivity;
import com.philliphsu.clock2.settings.SettingsActivity; import com.philliphsu.clock2.settings.SettingsActivity;
import com.philliphsu.clock2.timers.TimersFragment; import com.philliphsu.clock2.timers.TimersFragment;
@ -56,13 +55,17 @@ public class MainActivity extends BaseActivity {
mFab.setOnClickListener(new View.OnClickListener() { mFab.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, EditAlarmActivity.class); // Intent intent = new Intent(MainActivity.this, EditAlarmActivity.class);
// Call Fragment#startActivityForResult() instead of Activity#startActivityForResult() // // Call Fragment#startActivityForResult() instead of Activity#startActivityForResult()
// because we want the result to be handled in the Fragment, not in this Activity. // // because we want the result to be handled in the Fragment, not in this Activity.
// FragmentActivity does NOT deliver the result to the Fragment, i.e. your // // FragmentActivity does NOT deliver the result to the Fragment, i.e. your
// Fragment's onActivityResult() will NOT be called. // // Fragment's onActivityResult() will NOT be called.
mSectionsPagerAdapter.getCurrentFragment() // mSectionsPagerAdapter.getCurrentFragment()
.startActivityForResult(intent, AlarmsFragment.REQUEST_CREATE_ALARM); // .startActivityForResult(intent, AlarmsFragment.REQUEST_CREATE_ALARM);
Fragment f;
if ((f = mSectionsPagerAdapter.getCurrentFragment()) instanceof RecyclerViewFragment) {
((RecyclerViewFragment) f).onFabClick();
}
} }
}); });
} }

View File

@ -1,6 +1,5 @@
package com.philliphsu.clock2; package com.philliphsu.clock2;
import android.database.Cursor;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
@ -11,16 +10,20 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.philliphsu.clock2.model.BaseItemCursor;
import com.philliphsu.clock2.model.ObjectWithId;
import butterknife.Bind; import butterknife.Bind;
/** /**
* Created by Phillip Hsu on 7/26/2016. * Created by Phillip Hsu on 7/26/2016.
*/ */
public abstract class RecyclerViewFragment<T, public abstract class RecyclerViewFragment<T extends ObjectWithId,
VH extends BaseViewHolder<T>, VH extends BaseViewHolder<T>,
A extends BaseAdapter<T, VH>> // TODO: From AlarmsCursorAdapter, abstract it out and use that type here. C extends BaseItemCursor<T>,
A extends BaseCursorAdapter<T, VH, C>>
extends BaseFragment implements extends BaseFragment implements
LoaderManager.LoaderCallbacks<Cursor>, LoaderManager.LoaderCallbacks<C>,
OnListItemInteractionListener<T> { OnListItemInteractionListener<T> {
private A mAdapter; private A mAdapter;
@ -45,6 +48,12 @@ public abstract class RecyclerViewFragment<T,
return new LinearLayoutManager(getActivity()); return new LinearLayoutManager(getActivity());
} }
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(0, null, this);
}
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@ -55,15 +64,13 @@ public abstract class RecyclerViewFragment<T,
} }
@Override @Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { public void onLoadFinished(Loader<C> loader, C data) {
// TODO: Change the adapter type to one that supports Cursors as its dataset mAdapter.swapCursor(data);
// mAdapter.swapCursor(data);
} }
@Override @Override
public void onLoaderReset(Loader<Cursor> loader) { public void onLoaderReset(Loader<C> loader) {
// TODO: Change the adapter type to one that supports Cursors as its dataset mAdapter.swapCursor(null);
// mAdapter.swapCursor(null);
} }
/** /**

View File

@ -3,6 +3,7 @@ package com.philliphsu.clock2;
import android.os.SystemClock; import android.os.SystemClock;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import com.philliphsu.clock2.model.ObjectWithId;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -10,10 +11,9 @@ import java.util.concurrent.TimeUnit;
* Created by Phillip Hsu on 7/25/2016. * Created by Phillip Hsu on 7/25/2016.
*/ */
@AutoValue @AutoValue
public abstract class Timer { public abstract class Timer extends ObjectWithId {
private static final long MINUTE = TimeUnit.MINUTES.toMillis(1); private static final long MINUTE = TimeUnit.MINUTES.toMillis(1);
private long id;
private long endTime; private long endTime;
private long pauseTime; private long pauseTime;
@ -42,14 +42,6 @@ public abstract class Timer {
return new AutoValue_Timer(hour, minute, second, group, label); return new AutoValue_Timer(hour, minute, second, group, label);
} }
public long id() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long endTime() { public long endTime() {
return endTime; return endTime;
} }
@ -115,4 +107,25 @@ public abstract class Timer {
public boolean isRunning() { public boolean isRunning() {
return hasStarted() && pauseTime == 0; return hasStarted() && pauseTime == 0;
} }
/**
* TO ONLY BE CALLED BY TIMERDATABASEHELPER.
*/
public void setEndTime(long endTime) {
this.endTime = endTime;
}
/**
* TO ONLY BE CALLED BY TIMERDATABASEHELPER.
*/
public void setPauseTime(long pauseTime) {
this.pauseTime = pauseTime;
}
/**
* TO ONLY BE CALLED BY TIMERDATABASEHELPER.
*/
public long pauseTime() {
return pauseTime;
}
} }

View File

@ -13,7 +13,7 @@ import com.philliphsu.clock2.util.AlarmController;
/** /**
* Created by Phillip Hsu on 6/29/2016. * Created by Phillip Hsu on 6/29/2016.
* *
* TODO: Make this abstract for other data types. * TODO: Extend from BaseCursorAdapter
*/ */
public class AlarmsCursorAdapter extends RecyclerView.Adapter<AlarmViewHolder> { public class AlarmsCursorAdapter extends RecyclerView.Adapter<AlarmViewHolder> {
private static final String TAG = "AlarmsCursorAdapter"; private static final String TAG = "AlarmsCursorAdapter";

View File

@ -153,6 +153,7 @@ public class EditTimerActivity extends BaseActivity {
// TODO: Pass back an intent with the data, or make Timer parcelable // TODO: Pass back an intent with the data, or make Timer parcelable
// and pass back an instance of Timer. Consider overriding finish() // and pass back an instance of Timer. Consider overriding finish()
// and doing it there. // and doing it there.
setResult(RESULT_OK);
finish(); finish();
} }

View File

@ -0,0 +1,114 @@
package com.philliphsu.clock2.model;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.philliphsu.clock2.util.LocalBroadcastHelper;
/**
* Created by Phillip Hsu on 7/29/2016.
*/
public abstract class BaseDatabaseHelper<T extends ObjectWithId> extends SQLiteOpenHelper {
public static final String COLUMN_ID = "_id";
private final Context mAppContext;
/**
* @param context the Context with which the application context will be retrieved
* @param name the name of the database file. Because this is required by the SQLiteOpenHelper
* constructor, we can't, for instance, have an abstract getDatabaseFileName() that
* subclasses implement and the base class can call on their behalf.
* @param version the version
*/
public BaseDatabaseHelper(Context context, String name,
/*SQLiteDatabase.CursorFactory factory,*/
int version) {
super(context.getApplicationContext(), name, null, version);
mAppContext = context.getApplicationContext();
}
/**
* @return the table managed by this helper
*/
protected abstract String getTableName();
/**
* @return the ContentValues representing the item's properties.
* You do not need to put a mapping for {@link #COLUMN_ID}, since
* the database manages ids for us (if you created your table
* with {@link #COLUMN_ID} as an {@code INTEGER PRIMARY KEY}).
*/
protected abstract ContentValues toContentValues(T item);
/**
* @return optional String specifying the sort order
* to use when querying the database. The default
* implementation returns null, which may return
* queries unordered.
*/
protected String getQuerySortOrder() {
return null;
}
public long insertItem(T item) {
long id = getWritableDatabase().insert(
getTableName(), null, toContentValues(item));
item.setId(id);
notifyContentChanged();
return id;
}
public int updateItem(long id, T newItem) {
newItem.setId(id);
SQLiteDatabase db = getWritableDatabase();
int rowsUpdated = db.update(getTableName(),
toContentValues(newItem),
COLUMN_ID + " = " + id,
null);
notifyContentChanged();
return rowsUpdated;
}
public int deleteItem(T item) {
SQLiteDatabase db = getWritableDatabase();
int rowsDeleted = db.delete(getTableName(),
COLUMN_ID + " = " + item.getId(),
null);
notifyContentChanged();
return rowsDeleted;
}
public Cursor queryItem(long id) {
return queryItems(COLUMN_ID + " = " + id, "1");
}
public Cursor queryItems() {
// Select all rows and columns
return queryItems(null, null);
}
protected Cursor queryItems(String where, String limit) {
return getReadableDatabase().query(getTableName(),
null, // All columns
where, // Selection, i.e. where COLUMN_* = [value we're looking for]
null, // selection args, none b/c id already specified in selection
null, // group by
null, // having
getQuerySortOrder(), // order/sort by
limit); // limit
}
/**
* Broadcasts to any registered receivers that the data backed
* by this helper has changed, and so they should requery and
* update themselves as necessary.
*/
private void notifyContentChanged() {
LocalBroadcastHelper.sendBroadcast(mAppContext,
SQLiteCursorLoader.ACTION_CHANGE_CONTENT);
}
}

View File

@ -0,0 +1,38 @@
package com.philliphsu.clock2.model;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.util.Log;
/**
* Created by Phillip Hsu on 7/29/2016.
*/
public abstract class BaseItemCursor<T extends ObjectWithId> extends CursorWrapper {
private static final String TAG = "BaseItemCursor";
public BaseItemCursor(Cursor cursor) {
super(cursor);
}
/**
* @return an item instance configured for the current row,
* or null if the current row is invalid
*/
public abstract T getItem();
public long getId() {
if (isBeforeFirst() || isAfterLast()) {
Log.e(TAG, "Failed to retrieve id, cursor out of range");
return -1;
}
return getLong(getColumnIndexOrThrow(BaseDatabaseHelper.COLUMN_ID));
}
/**
* Helper method to determine boolean-valued columns.
* SQLite does not support a BOOLEAN data type.
*/
protected boolean isTrue(String columnName) {
return getInt(getColumnIndexOrThrow(columnName)) == 1;
}
}

View File

@ -0,0 +1,130 @@
package com.philliphsu.clock2.model;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;
import com.philliphsu.clock2.util.LocalBroadcastHelper;
/**
* Created by Phillip Hsu on 6/28/2016.
*
* Efficiently loads and holds a Cursor.
*/
public abstract class NewSQLiteCursorLoader<
T extends ObjectWithId,
C extends BaseItemCursor<T>>
extends AsyncTaskLoader<C> {
private static final String TAG = "SQLiteCursorLoader";
public static final String ACTION_CHANGE_CONTENT = "com.philliphsu.clock2.model.action.CHANGE_CONTENT";
private C mCursor;
private OnContentChangeReceiver mOnContentChangeReceiver;
public NewSQLiteCursorLoader(Context context) {
super(context);
}
protected abstract C loadCursor();
/* Runs on a worker thread */
@Override
public C loadInBackground() {
C cursor = loadCursor();
if (cursor != null) {
// Ensure that the content window is filled
// Ensure that the data is available in memory once it is
// passed to the main thread
cursor.getCount();
}
return cursor;
}
/* Runs on the UI thread */
@Override
public void deliverResult(C cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
// Close the old cursor because it is no longer needed.
// Because an existing cursor may be cached and redelivered, it is important
// to make sure that the old cursor and the new cursor are not the
// same before the old cursor is closed.
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
// Refer to the docs if you wish to understand the rest of the API as used below.
@Override
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (mOnContentChangeReceiver == null) {
mOnContentChangeReceiver = new OnContentChangeReceiver();
LocalBroadcastHelper.registerReceiver(getContext(),
mOnContentChangeReceiver, ACTION_CHANGE_CONTENT);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(C cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
if (mOnContentChangeReceiver != null) {
LocalBroadcastHelper.unregisterReceiver(getContext(),
mOnContentChangeReceiver);
mOnContentChangeReceiver = null;
}
}
private final class OnContentChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received content change event");
onContentChanged();
}
}
}

View File

@ -0,0 +1,18 @@
package com.philliphsu.clock2.model;
/**
* Created by Phillip Hsu on 7/29/2016.
*
* Superclass for objects that can be persisted in SQLite.
*/
public abstract class ObjectWithId {
private long id;
public final long getId() {
return id;
}
public final void setId(long id) {
this.id = id;
}
}

View File

@ -0,0 +1,132 @@
package com.philliphsu.clock2.model;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.philliphsu.clock2.Timer;
/**
* Created by Phillip Hsu on 7/29/2016.
*/
public class TimerDatabaseHelper extends BaseDatabaseHelper<Timer> {
private static final String TAG = "TimerDatabaseHelper";
private static final String DB_NAME = "timers.db";
private static final int VERSION_1 = 1;
private static final String TABLE_TIMERS = "timers";
// TODO: Consider making these public, so we can move TimerCursor to its own top-level class.
private static final String COLUMN_HOUR = "hour";
private static final String COLUMN_MINUTE = "minute";
private static final String COLUMN_SECOND = "second";
private static final String COLUMN_LABEL = "label";
// http://stackoverflow.com/q/24183958/5055032
// https://www.sqlite.org/lang_keywords.html
// GROUP is a reserved keyword, so your CREATE TABLE statement
// will not compile if you include this!
// private static final String COLUMN_GROUP = "group";
private static final String COLUMN_END_TIME = "end_time";
private static final String COLUMN_PAUSE_TIME = "pause_time";
private static final String SORT_ORDER =
COLUMN_HOUR + " ASC, "
+ COLUMN_MINUTE + " ASC, "
+ COLUMN_SECOND + " ASC, "
// All else equal, newer timers first
+ COLUMN_ID + " DESC";
public TimerDatabaseHelper(Context context) {
super(context, DB_NAME, VERSION_1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_TIMERS + " ("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COLUMN_HOUR + " INTEGER NOT NULL, "
+ COLUMN_MINUTE + " INTEGER NOT NULL, "
+ COLUMN_SECOND + " INTEGER NOT NULL, "
+ COLUMN_LABEL + " TEXT NOT NULL, "
// + COLUMN_GROUP + " TEXT NOT NULL, "
+ COLUMN_END_TIME + " INTEGER NOT NULL, "
+ COLUMN_PAUSE_TIME + " INTEGER NOT NULL);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// I don't think we need to drop current tables unless you make structural changes
// to the schema in the new version.
}
// =============================================================================================
// Overridden methods can have a more specific return type, as long as that type
// is a subtype of the original return type.
@Override
public TimerCursor queryItem(long id) {
return wrapInTimerCursor(queryItem(id));
}
@Override
public TimerCursor queryItems() {
return wrapInTimerCursor(super.queryItems());
}
@Override
protected TimerCursor queryItems(String where, String limit) {
return wrapInTimerCursor(super.queryItems(where, limit));
}
// =============================================================================================
@Override
protected String getTableName() {
return TABLE_TIMERS;
}
@Override
protected ContentValues toContentValues(Timer timer) {
ContentValues cv = new ContentValues();
cv.put(COLUMN_HOUR, timer.hour());
cv.put(COLUMN_MINUTE, timer.minute());
cv.put(COLUMN_SECOND, timer.second());
cv.put(COLUMN_LABEL, timer.label());
// cv.put(COLUMN_GROUP, timer.group());
cv.put(COLUMN_END_TIME, timer.endTime());
cv.put(COLUMN_PAUSE_TIME, timer.pauseTime());
return cv;
}
@Override
protected String getQuerySortOrder() {
return SORT_ORDER;
}
private TimerCursor wrapInTimerCursor(Cursor c) {
return new TimerCursor(c);
}
public static class TimerCursor extends BaseItemCursor<Timer> {
public TimerCursor(Cursor cursor) {
super(cursor);
}
@Override
public Timer getItem() {
if (isBeforeFirst() || isAfterLast())
return null;
int hour = getInt(getColumnIndexOrThrow(COLUMN_HOUR));
int minute = getInt(getColumnIndexOrThrow(COLUMN_MINUTE));
int second = getInt(getColumnIndexOrThrow(COLUMN_SECOND));
String label = getString(getColumnIndexOrThrow(COLUMN_LABEL));
// String group = getString(getColumnIndexOrThrow(COLUMN_GROUP));
Timer t = Timer.create(hour, minute, second, label, /*group*/"");
t.setEndTime(getInt(getColumnIndexOrThrow(COLUMN_END_TIME)));
t.setPauseTime(getInt(getColumnIndexOrThrow(COLUMN_PAUSE_TIME)));
return t;
}
}
}

View File

@ -0,0 +1,20 @@
package com.philliphsu.clock2.model;
import android.content.Context;
import com.philliphsu.clock2.Timer;
/**
* Created by Phillip Hsu on 7/29/2016.
*/
public class TimersListCursorLoader extends NewSQLiteCursorLoader<Timer, TimerDatabaseHelper.TimerCursor> {
public TimersListCursorLoader(Context context) {
super(context);
}
@Override
protected TimerDatabaseHelper.TimerCursor loadCursor() {
return new TimerDatabaseHelper(getContext()).queryItems();
}
}

View File

@ -0,0 +1,23 @@
package com.philliphsu.clock2.timers;
import android.view.ViewGroup;
import com.philliphsu.clock2.BaseCursorAdapter;
import com.philliphsu.clock2.OnListItemInteractionListener;
import com.philliphsu.clock2.Timer;
import com.philliphsu.clock2.model.TimerDatabaseHelper;
/**
* Created by Phillip Hsu on 7/29/2016.
*/
public class TimersCursorAdapter extends BaseCursorAdapter<Timer, TimerViewHolder, TimerDatabaseHelper.TimerCursor> {
public TimersCursorAdapter(OnListItemInteractionListener<Timer> listener) {
super(listener);
}
@Override
protected TimerViewHolder onCreateViewHolder(ViewGroup parent, OnListItemInteractionListener<Timer> listener) {
return new TimerViewHolder(parent, listener);
}
}

View File

@ -3,52 +3,52 @@ package com.philliphsu.clock2.timers;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.philliphsu.clock2.OnListItemInteractionListener; import com.philliphsu.clock2.RecyclerViewFragment;
import com.philliphsu.clock2.R;
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.timers.dummy.DummyContent; import com.philliphsu.clock2.model.TimerDatabaseHelper;
import com.philliphsu.clock2.model.TimersListCursorLoader;
import butterknife.ButterKnife; public class TimersFragment extends RecyclerViewFragment<
Timer,
TimerViewHolder,
TimerDatabaseHelper.TimerCursor,
TimersCursorAdapter> {
public static final int REQUEST_CREATE_TIMER = 0;
/** @Override
* TODO: Extend from RecyclerViewFragment. public void onActivityResult(int requestCode, int resultCode, Intent data) {
*/ // if (resultCode != Activity.RESULT_OK || data == null)
public class TimersFragment extends Fragment { // return;
TimerDatabaseHelper db = new TimerDatabaseHelper(getActivity());
public TimersFragment() { db.insertItem(Timer.create(1, 0, 0));
// Required empty public constructor
} }
@Override
public void onFabClick() {
Intent intent = new Intent(getActivity(), EditTimerActivity.class);
startActivityForResult(intent, REQUEST_CREATE_TIMER);
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, protected TimersCursorAdapter getAdapter() {
Bundle savedInstanceState) { return new TimersCursorAdapter(this);
View view = inflater.inflate(R.layout.fragment_alarms, container, false); }
ButterKnife.bind(this, view);
@Override
public Loader<TimerDatabaseHelper.TimerCursor> onCreateLoader(int id, Bundle args) {
return new TimersListCursorLoader(getActivity());
}
RecyclerView rv = ButterKnife.findById(view, R.id.list);
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
rv.setAdapter(new TimerAdapter(DummyContent.ITEMS, new OnListItemInteractionListener<Timer>() {
@Override @Override
public void onListItemClick(Timer item) { public void onListItemClick(Timer item) {
startActivity(new Intent(getActivity(), EditTimerActivity.class));
} }
@Override @Override
public void onListItemDeleted(Timer item) { public void onListItemDeleted(Timer item) {
} }
}));
return view;
}
} }

View File

@ -190,5 +190,5 @@
</string> </string>
<!-- TODO: Remove or change this placeholder text --> <!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string> <string name="title_activity_create_timer">CreateTimerActivity</string>
</resources> </resources>