使用内容提供程序删除数据时,AsyncTaskLoader 不刷新回收器视图
AsyncTaskLoader not refreshing the recycler view when the data is deleted using content provider
这是主要 class 列表的样子
package com.example.android.todolist;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.View;
import com.example.android.todolist.data.TaskContract;
public class MainActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
// Constants for logging and referring to a unique loader
private static final String TAG = MainActivity.class.getSimpleName();
private static final int TASK_LOADER_ID = 0;
// Member variables for the adapter and RecyclerView
private CustomCursorAdapter mAdapter;
RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set the RecyclerView to its corresponding view
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerViewTasks);
// 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
mAdapter = new CustomCursorAdapter(this);
mRecyclerView.setAdapter(mAdapter);
/*
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 swipeDir) {
// 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 = TaskContract.TaskEntry.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(TASK_LOADER_ID, null, MainActivity.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 fabButton = (FloatingActionButton) findViewById(R.id.fab);
fabButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Create a new intent to start an AddTaskActivity
Intent addTaskIntent = new Intent(MainActivity.this, AddTaskActivity.class);
startActivity(addTaskIntent);
}
});
/*
Ensure a loader is initialized and active. If the loader doesn't already exist, one is
created, otherwise the last created loader is re-used.
*/
getSupportLoaderManager().initLoader(TASK_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.
*/
@Override
protected void onResume() {
super.onResume();
// re-queries for all tasks
getSupportLoaderManager().restartLoader(TASK_LOADER_ID, null, this);
}
/**
* 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.
*/
@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs) {
return new AsyncTaskLoader<Cursor>(this) {
// Initialize a Cursor, this will hold all the task data
Cursor mTaskData = null;
// onStartLoading() is called when a loader first starts loading data
@Override
protected void onStartLoading() {
if (mTaskData != null) {
// Delivers any previously loaded data immediately
deliverResult(mTaskData);
} else {
// Force a 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(TaskContract.TaskEntry.CONTENT_URI,
null,
null,
null,
TaskContract.TaskEntry.COLUMN_PRIORITY);
} catch (Exception e) {
Log.e(TAG, "Failed to asynchronously load data.");
e.printStackTrace();
return null;
}
}
// deliverResult sends the result of the load, a Cursor, to the registered listener
public void deliverResult(Cursor data) {
mTaskData = data;
super.deliverResult(data);
}
};
}
/**
* Called when a previously created loader has finished its load.
*
* @param loader The Loader that has finished.
* @param data The data generated by the Loader.
*/
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Update the data that the adapter uses to create ViewHolders
mAdapter.swapCursor(data);
}
/**
* Called when a previously created loader is being reset, and thus
* making its data unavailable.
* onLoaderReset removes any references this activity had to the loader's data.
*
* @param loader The Loader that is being reset.
*/
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
class 使用内容提供商 sqlite 数据库。在删除内容的滑动操作中,如果数据发生变化,应直接通知。我认为这不会发生
下面是内容提供者class
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.todolist.data;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
import static com.example.android.todolist.data.TaskContract.TaskEntry.TABLE_NAME;
// Verify that TaskContentProvider extends from ContentProvider and implements required methods
public class TaskContentProvider extends ContentProvider {
// Define final integer constants for the directory of tasks and a single item.
// It's convention to use 100, 200, 300, etc for directories,
// and related ints (101, 102, ..) for items in that directory.
public static final int TASKS = 100;
public static final int TASK_WITH_ID = 101;
// CDeclare a static variable for the Uri matcher that you construct
private static final UriMatcher sUriMatcher = buildUriMatcher();
// Define a static buildUriMatcher method that associates URI's with their int match
/**
Initialize a new matcher object without any matches,
then use .addURI(String authority, String path, int match) to add matches
*/
public static UriMatcher buildUriMatcher() {
// Initialize a UriMatcher with no matches by passing in NO_MATCH to the constructor
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
/*
All paths added to the UriMatcher have a corresponding int.
For each kind of uri you may want to access, add the corresponding match with addURI.
The two calls below add matches for the task directory and a single item by ID.
*/
uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS, TASKS);
uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS + "/#", TASK_WITH_ID);
return uriMatcher;
}
// Member variable for a TaskDbHelper that's initialized in the onCreate() method
private TaskDbHelper mTaskDbHelper;
/* onCreate() is where you should initialize anything you’ll need to setup
your underlying data source.
In this case, you’re working with a SQLite database, so you’ll need to
initialize a DbHelper to gain access to it.
*/
@Override
public boolean onCreate() {
// Complete onCreate() and initialize a TaskDbhelper on startup
// [Hint] Declare the DbHelper as a global variable
Context context = getContext();
mTaskDbHelper = new TaskDbHelper(context);
return true;
}
// Implement insert to handle requests to insert a single new row of data
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
// Get access to the task database (to write new data to)
final SQLiteDatabase db = mTaskDbHelper.getWritableDatabase();
// Write URI matching code to identify the match for the tasks directory
int match = sUriMatcher.match(uri);
Uri returnUri; // URI to be returned
switch (match) {
case TASKS:
// Insert new values into the database
// Inserting values into tasks table
long id = db.insert(TABLE_NAME, null, values);
if ( id > 0 ) {
returnUri = ContentUris.withAppendedId(TaskContract.TaskEntry.CONTENT_URI, id);
} else {
throw new android.database.SQLException("Failed to insert row into " + uri);
}
break;
// Set the value for the returnedUri and write the default case for unknown URI's
// Default case throws an UnsupportedOperationException
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver if the uri has been changed, and return the newly inserted URI
getContext().getContentResolver().notifyChange(uri, null);
// Return constructed uri (this points to the newly inserted row of data)
return returnUri;
}
// Implement query to handle requests for data by URI
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Get access to underlying database (read-only for query)
final SQLiteDatabase db = mTaskDbHelper.getReadableDatabase();
// Write URI match code and set a variable to return a Cursor
int match = sUriMatcher.match(uri);
Cursor retCursor;
// Query for the tasks directory and write a default case
switch (match) {
// Query for the tasks directory
case TASKS:
retCursor = db.query(TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
// Default exception
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Set a notification URI on the Cursor and return that Cursor
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
// Return the desired Cursor
return retCursor;
}
// Implement delete to delete a single row of data
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
// Get access to the database and write URI matching code to recognize a single item
final SQLiteDatabase db = mTaskDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
// Keep track of the number of deleted tasks
int tasksDeleted; // starts as 0
// Write the code to delete a single row of data
// [Hint] Use selections to delete an item by its row ID
switch (match) {
// Handle the single item case, recognized by the ID included in the URI path
case TASK_WITH_ID:
// Get the task ID from the URI path
String id = uri.getPathSegments().get(1);
// Use selections/selectionArgs to filter for this ID
tasksDeleted = db.delete(TABLE_NAME, "_id=?", new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver of a change and return the number of items deleted
if (tasksDeleted != 0) {
// A task was deleted, set notification
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of tasks deleted
return tasksDeleted;
}
@Override
public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String getType(@NonNull Uri uri) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
两件事。
CustomCursorAdapter - 如果您从 CursorAdapter 扩展,请检查您的构造函数的超级方法,它有一个名为 flgs 的第三个参数。处理游标的自动查询部分。
由于您已经在使用 LoaderCallbacks,您可以直接使用游标加载器而不是 AsyncTaskLoader
@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs) {
return new CursorLoader(context, uri, projection, selection, mSelectionArgs, sortOrder);
}
这是主要 class 列表的样子
package com.example.android.todolist;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.View;
import com.example.android.todolist.data.TaskContract;
public class MainActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
// Constants for logging and referring to a unique loader
private static final String TAG = MainActivity.class.getSimpleName();
private static final int TASK_LOADER_ID = 0;
// Member variables for the adapter and RecyclerView
private CustomCursorAdapter mAdapter;
RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set the RecyclerView to its corresponding view
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerViewTasks);
// 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
mAdapter = new CustomCursorAdapter(this);
mRecyclerView.setAdapter(mAdapter);
/*
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 swipeDir) {
// 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 = TaskContract.TaskEntry.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(TASK_LOADER_ID, null, MainActivity.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 fabButton = (FloatingActionButton) findViewById(R.id.fab);
fabButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Create a new intent to start an AddTaskActivity
Intent addTaskIntent = new Intent(MainActivity.this, AddTaskActivity.class);
startActivity(addTaskIntent);
}
});
/*
Ensure a loader is initialized and active. If the loader doesn't already exist, one is
created, otherwise the last created loader is re-used.
*/
getSupportLoaderManager().initLoader(TASK_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.
*/
@Override
protected void onResume() {
super.onResume();
// re-queries for all tasks
getSupportLoaderManager().restartLoader(TASK_LOADER_ID, null, this);
}
/**
* 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.
*/
@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs) {
return new AsyncTaskLoader<Cursor>(this) {
// Initialize a Cursor, this will hold all the task data
Cursor mTaskData = null;
// onStartLoading() is called when a loader first starts loading data
@Override
protected void onStartLoading() {
if (mTaskData != null) {
// Delivers any previously loaded data immediately
deliverResult(mTaskData);
} else {
// Force a 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(TaskContract.TaskEntry.CONTENT_URI,
null,
null,
null,
TaskContract.TaskEntry.COLUMN_PRIORITY);
} catch (Exception e) {
Log.e(TAG, "Failed to asynchronously load data.");
e.printStackTrace();
return null;
}
}
// deliverResult sends the result of the load, a Cursor, to the registered listener
public void deliverResult(Cursor data) {
mTaskData = data;
super.deliverResult(data);
}
};
}
/**
* Called when a previously created loader has finished its load.
*
* @param loader The Loader that has finished.
* @param data The data generated by the Loader.
*/
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Update the data that the adapter uses to create ViewHolders
mAdapter.swapCursor(data);
}
/**
* Called when a previously created loader is being reset, and thus
* making its data unavailable.
* onLoaderReset removes any references this activity had to the loader's data.
*
* @param loader The Loader that is being reset.
*/
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
class 使用内容提供商 sqlite 数据库。在删除内容的滑动操作中,如果数据发生变化,应直接通知。我认为这不会发生
下面是内容提供者class
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.todolist.data;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
import static com.example.android.todolist.data.TaskContract.TaskEntry.TABLE_NAME;
// Verify that TaskContentProvider extends from ContentProvider and implements required methods
public class TaskContentProvider extends ContentProvider {
// Define final integer constants for the directory of tasks and a single item.
// It's convention to use 100, 200, 300, etc for directories,
// and related ints (101, 102, ..) for items in that directory.
public static final int TASKS = 100;
public static final int TASK_WITH_ID = 101;
// CDeclare a static variable for the Uri matcher that you construct
private static final UriMatcher sUriMatcher = buildUriMatcher();
// Define a static buildUriMatcher method that associates URI's with their int match
/**
Initialize a new matcher object without any matches,
then use .addURI(String authority, String path, int match) to add matches
*/
public static UriMatcher buildUriMatcher() {
// Initialize a UriMatcher with no matches by passing in NO_MATCH to the constructor
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
/*
All paths added to the UriMatcher have a corresponding int.
For each kind of uri you may want to access, add the corresponding match with addURI.
The two calls below add matches for the task directory and a single item by ID.
*/
uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS, TASKS);
uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS + "/#", TASK_WITH_ID);
return uriMatcher;
}
// Member variable for a TaskDbHelper that's initialized in the onCreate() method
private TaskDbHelper mTaskDbHelper;
/* onCreate() is where you should initialize anything you’ll need to setup
your underlying data source.
In this case, you’re working with a SQLite database, so you’ll need to
initialize a DbHelper to gain access to it.
*/
@Override
public boolean onCreate() {
// Complete onCreate() and initialize a TaskDbhelper on startup
// [Hint] Declare the DbHelper as a global variable
Context context = getContext();
mTaskDbHelper = new TaskDbHelper(context);
return true;
}
// Implement insert to handle requests to insert a single new row of data
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
// Get access to the task database (to write new data to)
final SQLiteDatabase db = mTaskDbHelper.getWritableDatabase();
// Write URI matching code to identify the match for the tasks directory
int match = sUriMatcher.match(uri);
Uri returnUri; // URI to be returned
switch (match) {
case TASKS:
// Insert new values into the database
// Inserting values into tasks table
long id = db.insert(TABLE_NAME, null, values);
if ( id > 0 ) {
returnUri = ContentUris.withAppendedId(TaskContract.TaskEntry.CONTENT_URI, id);
} else {
throw new android.database.SQLException("Failed to insert row into " + uri);
}
break;
// Set the value for the returnedUri and write the default case for unknown URI's
// Default case throws an UnsupportedOperationException
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver if the uri has been changed, and return the newly inserted URI
getContext().getContentResolver().notifyChange(uri, null);
// Return constructed uri (this points to the newly inserted row of data)
return returnUri;
}
// Implement query to handle requests for data by URI
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Get access to underlying database (read-only for query)
final SQLiteDatabase db = mTaskDbHelper.getReadableDatabase();
// Write URI match code and set a variable to return a Cursor
int match = sUriMatcher.match(uri);
Cursor retCursor;
// Query for the tasks directory and write a default case
switch (match) {
// Query for the tasks directory
case TASKS:
retCursor = db.query(TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
// Default exception
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Set a notification URI on the Cursor and return that Cursor
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
// Return the desired Cursor
return retCursor;
}
// Implement delete to delete a single row of data
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
// Get access to the database and write URI matching code to recognize a single item
final SQLiteDatabase db = mTaskDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
// Keep track of the number of deleted tasks
int tasksDeleted; // starts as 0
// Write the code to delete a single row of data
// [Hint] Use selections to delete an item by its row ID
switch (match) {
// Handle the single item case, recognized by the ID included in the URI path
case TASK_WITH_ID:
// Get the task ID from the URI path
String id = uri.getPathSegments().get(1);
// Use selections/selectionArgs to filter for this ID
tasksDeleted = db.delete(TABLE_NAME, "_id=?", new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver of a change and return the number of items deleted
if (tasksDeleted != 0) {
// A task was deleted, set notification
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of tasks deleted
return tasksDeleted;
}
@Override
public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String getType(@NonNull Uri uri) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
两件事。
CustomCursorAdapter - 如果您从 CursorAdapter 扩展,请检查您的构造函数的超级方法,它有一个名为 flgs 的第三个参数。处理游标的自动查询部分。
由于您已经在使用 LoaderCallbacks,您可以直接使用游标加载器而不是 AsyncTaskLoader
@Override public Loader<Cursor> onCreateLoader(int id, final Bundle loaderArgs) { return new CursorLoader(context, uri, projection, selection, mSelectionArgs, sortOrder); }