Here is one way to implement this set of functionality. All of the functionality described in the original question is implemented and is available here: Sample Application on GitHub. Also, if you have suggestions for improvement, please advise, either here or on GitHub.
Generally, there is a model held in the list activity, and that model is passed as an extra into the slide activity. Changes to the slide activity model are easily reflected there and in the database, and a bit of effort was required to allow the changes in the slide activity to appear in the list activity when the user pressed the back button.
The main activity onCreate
creates an SQLite database adapter and puts some data in there. It creates an ArrayList<Model>
and uses that to build the RecyclerView.Adapter
:
public class RecyclerSqlListActivity extends AppCompatActivity {
....
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_list);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView1);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
try {
repository = new DbSqlliteAdapter(this);
repository.open();
//repository.deleteAll();
//repository.insertSome();
modelList = repository.loadModelFromDatabase();// <<< This is select * from table into the modelList
Log.v(TAG, "The modelList has " + modelList.size() + " entries.");
recyclerViewAdapter = new MyRecyclerViewAdapter(this, modelList);
recyclerView.setAdapter(recyclerViewAdapter);
recyclerView.hasFixedSize();
} catch (Exception e) {
Log.v(TAG, "Exception in onCreate " + e.getMessage());
}
}
...
}
Here's the layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</LinearLayout>
The RecyclerView.Adapter
is where the listeners are. I listen for a click and a long click. The click starts the slide activity and the long click changes the database so that the icon shows or not. When the user takes action that changes data, I need to make sure the model, and database get updated and I need to notify the view that something has changed. Note that this implementation just manages things that have actually changed, as opposed to refreshing everything.
class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView iconImageView;
TextView nameTextView;
TextView secondLineTextView;
TextView dbItemTextView;
TextView hiddenTextView;
TextView descriptionTextView;
ViewHolder(View itemView) {
super(itemView);
iconImageView = (ImageView) itemView.findViewById(R.id.bIcon);
nameTextView = (TextView) itemView.findViewById(R.id.bName);
secondLineTextView = (TextView) itemView.findViewById(R.id.bSecondLine);
dbItemTextView = (TextView) itemView.findViewById(R.id.bDbItem);
hiddenTextView = (TextView) itemView.findViewById(R.id.bHidden);
descriptionTextView = (TextView) itemView.findViewById(R.id.bDescription);
}
}
private List<Model> mModelList;
private Context mContext;
MyRecyclerViewAdapter(Context context, List<Model> modelList) {
mContext = context;
mModelList = new ArrayList<>(modelList);
}
@Override
public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View modelView = inflater.inflate(R.layout.list_item, parent, false);
return new ViewHolder(modelView);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
final Model model = mModelList.get(position);
viewHolder.nameTextView.setText(model.getName());
viewHolder.secondLineTextView.setText(model.getSecond_line());
viewHolder.dbItemTextView.setText(model.getId() + "");
viewHolder.hiddenTextView.setText(model.getHidden());
viewHolder.descriptionTextView.setText(model.getDescription());
if ("F".equals(model.getHidden())) {
viewHolder.secondLineTextView.setVisibility(View.VISIBLE);
viewHolder.iconImageView.setVisibility(View.INVISIBLE);
} else {
viewHolder.secondLineTextView.setVisibility(View.INVISIBLE);
viewHolder.iconImageView.setVisibility(View.VISIBLE);
}
// DEFINE ACTIVITY THAT HAPPENS WHEN ITEM IS CLICKED
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.v(TAG, "setOnClickListener fired with view " + view); // view is RelativeLayout from list_item.xml
int position = mModelList.indexOf(model);
Log.v(TAG, "position was : " + position);
Intent intent = new Intent(mContext, DetailSlideActivity.class);
intent.putExtra(DetailSlideActivity.EXTRA_LIST_MODEL, (Serializable)mModelList);
intent.putExtra(DetailSlideActivity.EXTRA_POSITION, position);
((Activity)mContext).startActivityForResult(intent, RecyclerSqlListActivity.DETAIL_REQUEST);
}
});
// If the item is long-clicked, we want to change the icon in the model and in the database
viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
Log.v(TAG, "setOnLongClickListener fired with view " + view); // view is RelativeLayout from list_item.xml
Log.v(TAG, "setOnLongClickListener getTag method gave us position: " + view.getTag());
int position = mModelList.indexOf(model);
Log.v(TAG, "position was : " + position);
String hidden = model.getHidden();
Log.v(TAG, "hidden string was : " + hidden);
if ("F".equals(hidden)) {
model.setHidden("T");
DbSqlliteAdapter.update(model);
view.findViewById(R.id.bIcon).setVisibility(View.INVISIBLE);
} else {
model.setHidden("F");
view.findViewById(R.id.bIcon).setVisibility(View.VISIBLE);
}
Log.v(TAG, "updating the database");
DbSqlliteAdapter.update(model);
Log.v(TAG, "notifyItemChanged being called");
notifyItemChanged(position);
boolean longClickConsumed = true; // no more will happen :)
return longClickConsumed;
}
});
}
Rather than put all of the code here, I'll just put a subset, and more details can be found by going to the github link, above. But one last comment on how the app was designed to get the list of items that were altered during the slide activity. Each time a change happened in the slide activity, the position was saved at the same time the database was updated. Then, when the slide activity ended, onActivityResult()
pulled all of those positions and updated the model that is held in the original activity.
public class RecyclerSqlListActivity extends AppCompatActivity {
....
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if(requestCode == RecyclerSqlListActivity.DETAIL_REQUEST){
Log.v(TAG, "onActivityResult fired <<<<<<<<<< resultCode:" + resultCode);
//String[] changedItems = intent.getStringArrayExtra(RecyclerSqlListActivity.DETAIL_RESULTS); // We could return things we learned, such as which items were altered. Or we could just update everything
//modelList = repository.loadModelFromDatabase();// <<< This is select * from table into the modelList
Integer[] changedPositions = DbSqlliteAdapter.getChangedPositions();
for (Integer changedPosition : changedPositions) {
Model aModel = modelList.get(changedPosition);
DbSqlliteAdapter.loadModel(aModel);
recyclerViewAdapter.notifyItemChanged(changedPosition);
}
}
}
....
}
Here are a few of the classes that interact with the database. I decided against ContentProvider
because, according to the documentation, that's for sharing data between applications, not within one application.
class DbSqlliteAdapter {
....
static Model loadModel(Model model) {
Model dbModel = DbSqlliteAdapter.getById(model.getId() + "");
Log.v(TAG, "looked up " + model.getId() + " and it found " + dbModel.toString());
model.setId(dbModel.getId());
model.setName(dbModel.getName());
model.setSecond_line(dbModel.getSecond_line());
model.setDescription(dbModel.getDescription());
model.setHidden(dbModel.getHidden());
return model;
}
private static class DatabaseHelper extends SQLiteOpenHelper {....}
....
static void update(Model model) {
ContentValues values = fillModelValues(model);
Log.v(TAG, "Working on model that looks like this: " + model);
Log.v(TAG, "Updating record " + values.get(Model.ID) + " in the database.");
mDb.update(SQLITE_TABLE, values, Model.ID + "=?", new String[] {"" + values.get(Model.ID)});
Model resultInDb = getById("" + values.get(Model.ID));
Log.v(TAG, "after update, resultInDb: " + resultInDb);
}
static void update(Model model, int position) {
positionSet.add(position);
update(model);
}
static Integer[] getChangedPositions() {
Integer[] positions = positionSet.toArray(new Integer[0]);
positionSet.clear();
return positions;
}
....
}
