嘿,我正在开发一个保持便笺的android应用,我们可以从浮动按钮添加便笺,也可以通过向左或向右滑动来删除便笺。这运作良好。但是,当我想从溢出菜单中删除所有笔记时,它会删除它们,但仍显示所有笔记,当我重新加载应用程序时,它不会显示它们,因此不会动态更新用户界面。在菜单选项中,我还添加了一个用于插入虚拟注释以进行调试的插入虚拟数据选项,但是在我重新加载应用程序之前它不会更新。我添加了摘录的主要活动代码,我将其命名为CatalogActivity,并将自定义适配器类命名为NoteCursorAdapter。请忽略注释的代码部分。
public class CatalogActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<Cursor>{
/** Identifier for the pet data loader */
private static final int NOTE_LOADER_ID = 0;
/** Adapter for the ListView */
NoteCursorAdapter mCursorAdapter;
RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog);
// Set the RecyclerView to its corresponding view
mRecyclerView = findViewById(R.id.list);
// Set the layout for the RecyclerView to be a linear layout, which measures and
// positions items within a RecyclerView into a linear list
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
// Initialize the adapter and attach it to the RecyclerView
mCursorAdapter = new NoteCursorAdapter(this);
mRecyclerView.setAdapter(mCursorAdapter);
/*
Add a touch helper to the RecyclerView to recognize when a user swipes to delete an item.
An ItemTouchHelper enables touch behavior (like swipe and move) on each ViewHolder,
and uses callbacks to signal when a user is performing these actions.
*/
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
// Called when a user swipes left or right on a ViewHolder
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// Here is where you'll implement swipe to delete
// COMPLETED (1) Construct the URI for the item to delete
//[Hint] Use getTag (from the adapter code) to get the id of the swiped item
// Retrieve the id of the task to delete
int id = (int) viewHolder.itemView.getTag();
// Build appropriate uri with String row id appended
String stringId = Integer.toString(id);
Uri uri = NoteEntry.CONTENT_URI;
uri = uri.buildUpon().appendPath(stringId).build();
// COMPLETED (2) Delete a single row of data using a ContentResolver
getContentResolver().delete(uri, null, null);
// COMPLETED (3) Restart the loader to re-query for all tasks after a deletion
//getSupportLoaderManager().restartLoader(NOTE_LOADER_ID, null, CatalogActivity.this);
// TODO Check this exception
getLoaderManager().restartLoader(NOTE_LOADER_ID, null, CatalogActivity.this);
}
}).attachToRecyclerView(mRecyclerView);
/*
Set the Floating Action Button (FAB) to its corresponding View.
Attach an OnClickListener to it, so that when it's clicked, a new intent will be created
to launch the AddTaskActivity.
*/
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(CatalogActivity.this, EditorActivity.class);
startActivity(intent);
}
});
getLoaderManager().initLoader(NOTE_LOADER_ID, null, this);
}
/**
* This method is called after this activity has been paused or restarted.
* Often, this is after new data has been inserted through an AddTaskActivity,
* so this restarts the loader to re-query the underlying data for any changes.
*/
protected void onResume() {
super.onResume();
// Re-queries for all notes
getLoaderManager().restartLoader(NOTE_LOADER_ID, null, CatalogActivity.this);
}
private void insertNotes() {
// Create a ContentValues object where column names are the keys,
// and Particular note attributes are the values
ContentValues values = new ContentValues();
values.put(NoteEntry.COLUMN_NOTE_TITLE, "Test");
values.put(NoteEntry.COLUMN_NOTE_DETAILS, "SQLite");
values.put(NoteEntry.COLUMN_NOTE_PRIORITY, 0);
// Insert a new row for a note into the provider using the ContentResolver.
// Use the {@link NoteEntry#CONTENT_URI} to indicate that we want to insert
// into the notes database table.
// Receive the new content URI that will allow us to access Particular data in the future.
Uri newUri = getContentResolver().insert(NoteEntry.CONTENT_URI, values);
}
/*
* Helper method to delete all notes in the database.
*/
private void deleteAllNotes() {
int rowsDeleted = getContentResolver().delete(NoteEntry.CONTENT_URI, null, null);
Log.v("CatalogActivity", rowsDeleted + " rows deleted from note database");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu options from the res/menu/menu_catalog.xml file.
// This adds menu items to the app bar.
getMenuInflater().inflate(R.menu.menu_catalog, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// User clicked on a menu option in the app bar overflow menu
switch (item.getItemId()) {
// Respond to a click on the "Insert dummy data" menu option
case R.id.action_insert_dummy_data:
insertNotes();
return true;
// Respond to a click on the "Delete all entries" menu option
case R.id.action_delete_all_entries:
deleteAllNotes();
return true;
}
return super.onOptionsItemSelected(item);
}
* Instantiates and returns a new AsyncTaskLoader with the given ID.
* This loader will return task data as a Cursor or null if an error occurs.
*
* Implements the required callbacks to take care of loading data at all stages of loading.
*/
@SuppressLint("StaticFieldLeak")
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new AsyncTaskLoader<Cursor>(this) {
// Initialize a Cursor, this will hold all the task data
Cursor mNoteData = null;
// onStartLoading() is called when a loader first starts loading data
@Override
protected void onStartLoading() {
if (mNoteData != null) {
// Delivers any previously loaded data immediately
deliverResult(mNoteData);
} else {
// Force new load
forceLoad();
}
}
// loadInBackground() performs asynchronous loading of data
@Override
public Cursor loadInBackground() {
// Will implement to load data
// Query and load all task data in the background; sort by priority
// [Hint] use a try/catch block to catch any errors in loading data
try {
return getContentResolver().query(NoteContract.NoteEntry.CONTENT_URI,
null,
null,
null,
NoteEntry.COLUMN_NOTE_PRIORITY);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// deliverResult sends the result of the load, a Cursor, to the registered listener
public void deliverResult(Cursor data) {
mNoteData = data;
super.deliverResult(data);
}
};
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Update {@link NoteCursorAdapter} with this new cursor containing updated pet data
mCursorAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// Callback called when the data needs to be deleted
mCursorAdapter.swapCursor(null);
}
}
/**
* {@link NoteCursorAdapter} is an adapter for a list or grid view
* that uses a {@link Cursor} of pet data as its data source. This adapter knows
* how to create list items for each row of pet data in the {@link Cursor}.
*/
public class NoteCursorAdapter
extends RecyclerView.Adapter<NoteCursorAdapter.TaskViewHolder> {
// Class variables for the Cursor that holds task data and the Context
private Cursor mCursor;
private Context mContext;
public NoteCursorAdapter(Context mContext) {
this.mContext = mContext;
}
@NonNull
@Override
public TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// Inflate the list_item layout to a view
View view = LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false);
return new TaskViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull NoteCursorAdapter.TaskViewHolder holder, int position) {
// Find the columns of note attributes that we're interested in
int idColoumnIndex = mCursor.getColumnIndex(NoteContract.NoteEntry._ID);
int titleColumnIndex = mCursor.getColumnIndex(NoteContract.NoteEntry.COLUMN_NOTE_TITLE);
int detailColumnIndex = mCursor.getColumnIndex(NoteContract.NoteEntry.COLUMN_NOTE_DETAILS);
mCursor.moveToPosition(position); // get to the right location in the cursor
// Determine the values of the wanted data
final int id = mCursor.getInt(idColoumnIndex);
String title = mCursor.getString(titleColumnIndex);
String details = mCursor.getString(detailColumnIndex);
// Set values
holder.itemView.setTag(id);
holder.titleTextView.setText(title);
holder.detailsTextView.setText(title);
}
@Override
public int getItemCount() {
if (mCursor == null) {
return 0;
}
return mCursor.getCount();
}
/**
* When data changes and a re-query occurs, this function swaps the old Cursor
* with a newly updated Cursor (Cursor c) that is passed in.
*/
public Cursor swapCursor(Cursor c) {
// check if this cursor is the same as the previous cursor (mCursor)
if (mCursor == c) {
return null;
}
Cursor temp = mCursor;
this.mCursor = c;
//check if this is a valid cursor, then update the cursor
if (c != null){
this.notifyDataSetChanged();
}
return temp;
}
// Inner class for creating View Holders.
class TaskViewHolder extends RecyclerView.ViewHolder {
TextView titleTextView;
TextView detailsTextView;
public TaskViewHolder(View itemView) {
super(itemView);
titleTextView = itemView.findViewById(R.id.titleNote);
detailsTextView = itemView.findViewById(R.id.detailsNote);
}
}
}