Use loader to query for a cursor for the list adapter

This commit is contained in:
Phillip Hsu
2016-06-29 04:01:46 -07:00
parent 11c4be68b9
commit 7d0718387f
6 changed files with 289 additions and 129 deletions
@@ -0,0 +1,68 @@
package com.philliphsu.clock2.alarms;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.ViewGroup;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.OnListItemInteractionListener;
import com.philliphsu.clock2.model.AlarmDatabaseHelper.AlarmCursor;
/**
* Created by Phillip Hsu on 6/29/2016.
*
* TODO: Make this abstract for other data types.
*/
public class AlarmsCursorAdapter extends RecyclerView.Adapter<AlarmViewHolder> {
private static final String TAG = "AlarmsCursorAdapter";
private final OnListItemInteractionListener<Alarm> mListener;
private AlarmCursor mCursor;
public AlarmsCursorAdapter(OnListItemInteractionListener<Alarm> listener) {
mListener = listener;
setHasStableIds(true); // TODO: why do we need this?
}
@Override
public AlarmViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new AlarmViewHolder(parent, mListener);
}
@Override
public void onBindViewHolder(AlarmViewHolder holder, int position) {
if (!mCursor.moveToPosition(position)) {
Log.e(TAG, "Failed to bind alarm " + position);
return;
}
holder.onBind(mCursor.getAlarm());
}
@Override
public int getItemCount() {
return mCursor == null ? 0 : mCursor.getCount();
}
@Override
public long getItemId(int position) {
if (mCursor == null || !mCursor.moveToPosition(position)) {
return super.getItemId(position); // -1
}
return mCursor.getId();
}
// TODO: Cursor param should be the appropriate subclass?
public void swapCursor(Cursor cursor) {
if (mCursor == cursor) {
return;
}
if (mCursor != null) {
mCursor.close();
}
mCursor = (AlarmCursor) cursor;
// There is no way to notify the adapter of individual
// item changes when the dataset is a cursor.
notifyDataSetChanged();
}
}
@@ -1,8 +1,10 @@
package com.philliphsu.clock2.alarms;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -12,6 +14,7 @@ import android.view.ViewGroup;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.OnListItemInteractionListener;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.model.AlarmsListCursorLoader;
import com.philliphsu.clock2.model.BaseRepository;
import com.philliphsu.clock2.model.DatabaseManager;
@@ -24,10 +27,15 @@ import butterknife.ButterKnife;
* Activities containing this fragment MUST implement the {@link OnAlarmInteractionListener}
* interface.
*/
public class AlarmsFragment extends Fragment implements BaseRepository.DataObserver<Alarm> {
// TODO: Use native fragments since we're targeting API >=19?
// TODO: Use native LoaderCallbacks.
public class AlarmsFragment extends Fragment implements
BaseRepository.DataObserver<Alarm>, LoaderCallbacks<Cursor> {
private OnAlarmInteractionListener mListener;
@Deprecated
private AlarmsAdapter mAdapter;
private AlarmsCursorAdapter mCursorAdapter;
private DatabaseManager mDatabaseManager;
@Bind(R.id.list) RecyclerView mList;
@@ -56,6 +64,8 @@ public class AlarmsFragment extends Fragment implements BaseRepository.DataObser
// TODO Read arguments
}
// Initialize the loader to load the list of runs
getLoaderManager().initLoader(0, null, this);
mDatabaseManager = DatabaseManager.getInstance(getActivity());
}
@@ -67,8 +77,12 @@ public class AlarmsFragment extends Fragment implements BaseRepository.DataObser
// Set the adapter
Context context = view.getContext();
mList.setLayoutManager(new LinearLayoutManager(context));
// TODO: Create a new adapter subclass with constructor that
// has no dataset param. The Loader will set the Cursor after it
// has finished loading it.
mAdapter = new AlarmsAdapter(mDatabaseManager.getAlarms(), mListener);
mList.setAdapter(mAdapter);
mCursorAdapter = new AlarmsCursorAdapter(mListener);
mList.setAdapter(mCursorAdapter);
return view;
}
@@ -84,6 +98,7 @@ public class AlarmsFragment extends Fragment implements BaseRepository.DataObser
super.onResume();
// TODO: Need to refresh the list's adapter for any item changes. Consider doing this in
// onNewActivity().
getLoaderManager().restartLoader(0, null, this);
}
@Override
@@ -125,6 +140,23 @@ public class AlarmsFragment extends Fragment implements BaseRepository.DataObser
mAdapter.updateItem(oldItem, newItem);
}
@Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new AlarmsListCursorLoader(getActivity());
}
@Override
public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
// Called on the main thread after loading is complete
mCursorAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(android.support.v4.content.Loader<Cursor> loader) {
// The adapter's current cursor should not be used anymore
mCursorAdapter.swapCursor(null);
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated