I have an error when I try to read a table. I have a database with several table but my uri seems to not match.
My Content Provider :
public class CardContentProvider extends ContentProvider {
private StockCard stock;
public static String authority = "com.example.jean.cartememoire.CardContentProvider";
private static String path ="Cartes_table";
public static final String _ID = "_id";
public static final String THEME = "THEME";
public static final String QUESTION = "QUESTION";
public static final String REPONSE = "REPONSE";
public static final String DIFFICULTE = "DIFFICULTE"; //# = un chiffre
public static final String STOCK_TABLE = "Cartes_table";
public static final String STOCK_FACILE = "";
public static final String STOCK_NORMAL = "Cartes_tableCartes_table_facile_normal";
public static final String STOCK_DIFFICILE = "Cartes_table_difficile";
public static final String STOCK_EXTREME = "Cartes_table_extreme";
public static final String STOCK_IMPOSSIBLE = "Cartes_table_impossible";
private static final int ID_STOCK_TABLE = 1;
public static final int ID_FACILE = 2;
public static final int ID_NORMAL = 3;
public static final int ID_DIFFICILE = 4;
public static final int ID_EXTREME = 5;
public static final int ID_IMPOSSIBLE = 6;
private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
matcher.addURI(authority, STOCK_TABLE, ID_STOCK_TABLE);
matcher.addURI(authority, STOCK_TABLE+"/*", ID_STOCK_TABLE);
matcher.addURI(authority, STOCK_FACILE+"/*", ID_FACILE);
matcher.addURI(authority, STOCK_NORMAL+"/*", ID_NORMAL);
matcher.addURI(authority, STOCK_DIFFICILE+"/*", ID_DIFFICILE);
matcher.addURI(authority, STOCK_EXTREME+"/*", ID_EXTREME);
matcher.addURI(authority, STOCK_IMPOSSIBLE+"/*", ID_IMPOSSIBLE);
}
#Override
public boolean onCreate() {
stock = StockCard.getInstance(getContext());
return true;
}
#Nullable
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = stock.getReadableDatabase();
int code = matcher.match(uri);
Cursor cursor;
switch (code)
{
case ID_STOCK_TABLE:
Log.d("Uri provider = "+code+" ", uri.toString()+" ");
cursor = db.query(STOCK_TABLE, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case ID_FACILE:
cursor = db.query(STOCK_FACILE, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case ID_NORMAL:
cursor = db.query(STOCK_NORMAL, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case ID_DIFFICILE:
cursor = db.query(STOCK_DIFFICILE, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case ID_EXTREME:
cursor = db.query(STOCK_EXTREME, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case ID_IMPOSSIBLE:
cursor = db.query(STOCK_IMPOSSIBLE, projection, selection,
selectionArgs, null, null, sortOrder);
break;
default:
//long u = ContentUris.parseId(uri);
Log.d("Uri provider = "+code+" ", uri.toString()+" ");
throw new UnsupportedOperationException("Pas encore implémenté");
}
return cursor;
}
#Nullable
#Override
public String getType(Uri uri) {
return null;
}
#Nullable
#Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = stock.getWritableDatabase();
int code = matcher.match(uri);
long id;
Uri.Builder builder = new Uri.Builder();
switch(code)
{
case ID_STOCK_TABLE:
id = db.insert(STOCK_TABLE, null, values);
builder.appendPath(STOCK_TABLE);
break;
case ID_FACILE:
id = db.insert(STOCK_FACILE, null, values);
builder.appendPath(STOCK_FACILE);
break;
case ID_NORMAL:
id = db.insert(STOCK_NORMAL, null, values);
builder.appendPath(STOCK_NORMAL);
break;
case ID_DIFFICILE:
id = db.insert(STOCK_DIFFICILE, null, values);
builder.appendPath(STOCK_DIFFICILE);
break;
case ID_EXTREME:
id = db.insert(STOCK_EXTREME, null, values);
builder.appendPath(STOCK_EXTREME);
break;
case ID_IMPOSSIBLE:
id = db.insert(STOCK_IMPOSSIBLE, null, values);
builder.appendPath(STOCK_IMPOSSIBLE);
break;
default:
throw new UnsupportedOperationException("Pas encore implémenté");
}
builder.authority(authority);
builder = ContentUris.appendId(builder, id);
return builder.build();
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = stock.getWritableDatabase();
int code = matcher.match(uri);
int i;
long id;
switch(code)
{
case ID_STOCK_TABLE:
id = ContentUris.parseId(uri);
i = db.delete(STOCK_TABLE, "_id=" + id, null);
break;
case ID_FACILE:
id = ContentUris.parseId(uri);
i = db.delete(STOCK_FACILE, "_id=" + id, null);
break;
case ID_NORMAL:
id = ContentUris.parseId(uri);
i = db.delete(STOCK_NORMAL, "_id=" + id, null);
break;
case ID_DIFFICILE:
id = ContentUris.parseId(uri);
i = db.delete(STOCK_DIFFICILE, "_id=" + id, null);
break;
case ID_EXTREME:
id = ContentUris.parseId(uri);
i = db.delete(STOCK_EXTREME, "_id=" + id, null);
break;
case ID_IMPOSSIBLE:
id = ContentUris.parseId(uri);
i = db.delete(STOCK_IMPOSSIBLE, "_id=" + id, null);
break;
default:
throw new UnsupportedOperationException("Pas encore implémenté");
}
return 0;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
My Fragment class that contains my Loader, in my function databaseview, I put my rows inside a List View :
public class ViewDeck extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
public static final String authority = "com.example.jean.cartememoire.CardContentProvider";
public String[] from;
public final int[] to = {R.id.idList, R.id.themeList, R.id.questionList, R.id.reponseList, R.id.difficultList};
StockCard stock;
ViewGroup container;
ListView listView;
SimpleCursorAdapter adapter;
Cursor cursor;
private String focus;
private ArrayList<String> data = new ArrayList<String>();
private String table_name;
public ViewDeck()
{
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup c,
Bundle savedInstanceState) {
container = c;
View view = inflater.inflate(R.layout.fragment_view_card_editor, container, false);
stock = StockCard.getInstance(container.getContext());
from = new String[]{stock._ID,
stock.THEME,
stock.QUESTION,
stock.REPONSE,
stock.DIFFICULTE};
// Inflate the layout for this fragment
if (container != null) {
container.removeAllViews();
}
Bundle f = getArguments();
focus = getStockName(f.getInt("f"));
databaseView(view);
return view;
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri.Builder builder = new Uri.Builder();
Uri uri = builder.scheme("content").authority(authority)
.appendPath("Cartes_table_facile").build();
System.out.println("URI : "+uri.toString());
//Log.d("Uri provider = "+code+" ", uri.toString()+" ");
return new CursorLoader(container.getContext(), uri, from,
null, null, null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
public String getStockName(int d)
{
switch(d+1)
{
case CardContentProvider.ID_FACILE:
return CardContentProvider.STOCK_FACILE;
case CardContentProvider.ID_NORMAL:
return CardContentProvider.STOCK_NORMAL;
case CardContentProvider.ID_DIFFICILE:
return CardContentProvider.STOCK_DIFFICILE;
case CardContentProvider.ID_EXTREME:
return CardContentProvider.STOCK_EXTREME;
case CardContentProvider.ID_IMPOSSIBLE:
return CardContentProvider.STOCK_IMPOSSIBLE;
default:
throw new UnsupportedOperationException("Difficulté inconnue");
}
}
public void databaseView(View view)
{
listView = (ListView) view.findViewById(R.id.listView);
System.out.println("DANS DATABASEVIEW");
adapter = new SimpleCursorAdapter(container.getContext(), R.layout.card_stock, null, from, to,0);
listView.setAdapter(adapter);
if(cursor != null)
cursor.close();
LoaderManager manager = getLoaderManager();
manager.initLoader(0, null, this);
if(cursor != null)
cursor.close();
System.out.println("CA GAZ");
}
}
EDIT : My error :
01-04 17:45:45.507 28655-28691/? E/AndroidRuntime: FATAL EXCEPTION: ModernAsyncTask #1
Process: com.example.jean.cartememoire, PID: 28655
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:153)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.UnsupportedOperationException: Pas encore implémenté
at com.example.jean.cartememoire.CardContentProvider.query(CardContentProvider.java:101)
at android.content.ContentProvider.query(ContentProvider.java:1017)
at android.content.ContentProvider$Transport.query(ContentProvider.java:238)
at android.content.ContentResolver.query(ContentResolver.java:491)
at android.support.v4.content.ContentResolverCompatJellybean.query(ContentResolverCompatJellybean.java:29)
at android.support.v4.content.ContentResolverCompat$ContentResolverCompatImplJB.query(ContentResolverCompat.java:57)
at android.support.v4.content.ContentResolverCompat.query(ContentResolverCompat.java:125)
at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:59)
at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:37)
at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:296)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:54)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:42)
at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:133)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Related
I have problem while deleting data from database. I have button which is toggle between two states. Adding data to database and removing data from database. Here's the code:
//Method for adding or removing movies in favorite movie database
public long toggleFav(MovieData movieData) {
ContentValues cv = new ContentValues();
boolean favorite = isFav(movieData.getTitle());
if(favorite) {
favDb.delete(FavoriteContract.FavoriteEntry.TABLE_NAME,
FavoriteContract.FavoriteEntry.COLUMN_ID, null);
mFavoriteImage.setImageResource(R.drawable.fav_ic_no);
movieData.setIsFav(false);
Toast.makeText(MovieDetails.this, getString(R.string.remove_fav),
Toast.LENGTH_SHORT).show();
} else {
cv.put(FavoriteContract.FavoriteEntry.COLUMN_ID, movieData.getMovieId());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_POSTER, movieData.getPoster());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_TITLE, movieData.getTitle());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_RELEASE_DATE, movieData.getReleaseDate());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_AVERAGE_VOTE, movieData.getRating());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_SYNOPSIS, movieData.getSynopsis());
mFavoriteImage.setImageResource(R.drawable.fav_ic_selected);
Toast.makeText(MovieDetails.this, getString(R.string.add_fav),
Toast.LENGTH_SHORT).show();
}
return favDb.insert(FavoriteContract.FavoriteEntry.TABLE_NAME, null, cv);
}
On first click data is saved perfectly, but on second click data ''is removed'' but I get this strange error ...
04-05 14:57:18.540 11162-11162/com.example.android.popularmovies1 E/SQLiteLog: (1) near "null": syntax error
04-05 14:57:18.541 11162-11162/com.example.android.popularmovies1 E/SQLiteDatabase: Error inserting
android.database.sqlite.SQLiteException: near "null": syntax error (code 1): , while compiling: INSERT INTO fav_movies(null) VALUES (NULL)
Also, I have activity were I can see saved data, and if click button for saving it is listed on that activity. The problem is if I from database activity remove data from database, that data removes only when I leave that activity and then go back ...
Here's provider for database
public class FavoritesProvider extends ContentProvider {
public static final int FAVORITES = 100;
public static final int FAVORITES_WITH_ID = 101;
private FavoriteDbHelper mFavoriteDbHelper;
private static final UriMatcher sUriMatcher = buildUriMatcher();
public static UriMatcher buildUriMatcher() {
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(FavoriteContract.AUTHORITY, FavoriteContract.FAV_PATH, FAVORITES);
uriMatcher.addURI(FavoriteContract.AUTHORITY,
FavoriteContract.FAV_PATH + "/#", FAVORITES_WITH_ID);
return uriMatcher;
}
#Override
public boolean onCreate() {
Context context = getContext();
mFavoriteDbHelper = new FavoriteDbHelper(context);
return true;
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, #Nullable String selection,
#Nullable String[] selectionArgs, #Nullable String sortOrder) {
final SQLiteDatabase db = mFavoriteDbHelper.getReadableDatabase();
int match = sUriMatcher.match(uri);
Cursor retCursor;
switch(match) {
case FAVORITES:
retCursor = db.query(FavoriteContract.FavoriteEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
case FAVORITES_WITH_ID:
String id = uri.getPathSegments().get(1);
String mSelection = FavoriteContract.FavoriteEntry.COLUMN_ID;
String[] mSelectionArgs = new String[]{id};
retCursor = db.query(FavoriteContract.FavoriteEntry.TABLE_NAME,
projection,
mSelection,
mSelectionArgs,
null,
null,
sortOrder);
break;
default:
throw new UnsupportedOperationException("Uknown uri: " + uri);
}
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
#Nullable
#Override
public String getType(#NonNull Uri uri) {
int match = sUriMatcher.match(uri);
switch(match) {
case FAVORITES:
return "vnd.android.cursor.dir" + "/" + FavoriteContract.AUTHORITY + "/" +
FavoriteContract.FAV_PATH;
case FAVORITES_WITH_ID:
return "vnd.android.cursor.item" + "/" + FavoriteContract.AUTHORITY + "/" +
FavoriteContract.FAV_PATH;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
#Nullable
#Override
public Uri insert(#NonNull Uri uri, ContentValues values) {
final SQLiteDatabase db = mFavoriteDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
Uri retUri;
switch(match) {
case FAVORITES:
long id = db.insert(FavoriteContract.FavoriteEntry.TABLE_NAME,
null, values);
if(id > 0) {
retUri = ContentUris.withAppendedId(FavoriteContract
.FavoriteEntry.CONTENT_URI, id);
} else {
throw new android.database.SQLException("Failed to insert row into " + id);
}
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return retUri;
}
#Override
public int delete(#NonNull Uri uri, String selection,
String[] selectionArgs) {
final SQLiteDatabase db = mFavoriteDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
int favDeleted;
switch(match) {
case FAVORITES_WITH_ID:
String id = uri.getPathSegments().get(1);
favDeleted = db.delete(FavoriteContract.FavoriteEntry.TABLE_NAME,
FavoriteContract.FavoriteEntry.COLUMN_ID, new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if(favDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return favDeleted;
}
#Override
public int update(#NonNull Uri uri, #Nullable ContentValues values,
#Nullable String selection, #Nullable String[] selectionArgs) {
int match = sUriMatcher.match(uri);
int favUpdated;
switch(match) {
case FAVORITES_WITH_ID:
String id = uri.getPathSegments().get(1);
favUpdated = mFavoriteDbHelper.getWritableDatabase().update(
FavoriteContract.FavoriteEntry.TABLE_NAME, values,
FavoriteContract.FavoriteEntry.COLUMN_ID, new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if(favUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return favUpdated;
}
}
When the if statement is executed (favourite = true), nothing is added to your content values, and then in the last line you try insert into the database with no values, maybe just return -1 in the last bit of the if statement and move the final return statement into the else
maybe like this
public long toggleFav(MovieData movieData) {
boolean favorite = isFav(movieData.getTitle());
if(favorite) {
favDb.delete(FavoriteContract.FavoriteEntry.TABLE_NAME, FavoriteContract.FavoriteEntry.COLUMN_ID, null);
mFavoriteImage.setImageResource(R.drawable.fav_ic_no);
movieData.setIsFav(false);
Toast.makeText(MovieDetails.this, getString(R.string.remove_fav), Toast.LENGTH_SHORT).show();
return -1; // favourite deleted
} else {
ContentValues cv = new ContentValues();
cv.put(FavoriteContract.FavoriteEntry.COLUMN_ID, movieData.getMovieId());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_POSTER, movieData.getPoster());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_TITLE, movieData.getTitle());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_RELEASE_DATE, movieData.getReleaseDate());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_AVERAGE_VOTE, movieData.getRating());
cv.put(FavoriteContract.FavoriteEntry.COLUMN_SYNOPSIS, movieData.getSynopsis());
mFavoriteImage.setImageResource(R.drawable.fav_ic_selected);
Toast.makeText(MovieDetails.this, getString(R.string.add_fav), Toast.LENGTH_SHORT).show();
return favDb.insert(FavoriteContract.FavoriteEntry.TABLE_NAME, null, cv);
}
}
I have a Content Provider that can create one type of database. My database contains 5 columns and one table, and with my program, I want to be able to create a new table with the same columns as my first table. How can I change my Content Provider to do this ? I need to mach some uri, but how can I do this will I am in my program ?
My columns are :
_id, THEME, QUESTION, REPONSE, DIFFICULTE
Here is my Content Provider :
public class CardContentProvider extends ContentProvider {
private StockCard stock;
public static String authority = "com.example.jean.cartememoire.CardContentProvider";
private static String path ="Cartes_table";
public static final String _ID = "_id";
public static final String THEME = "THEME";
public static final String QUESTION = "QUESTION";
public static final String REPONSE = "REPONSE";
public static final String DIFFICULTE = "DIFFICULTE"; //# = un chiffre
public static final String STOCK_TABLE = "Cartes_table";
private static final int ID_STOCK_TABLE = 1;
private static final int ID_THEME = 2;
private static final int ID_QUESTION = 3;
private static final int ID_REPONSE = 4;
private static final int ID_DIFFICULTE = 5;
private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
matcher.addURI(authority, STOCK_TABLE, ID_STOCK_TABLE);
matcher.addURI(authority, STOCK_TABLE+"/*", ID_STOCK_TABLE);
}
#Override
public boolean onCreate() {
stock = StockCard.getInstance(getContext());
return true;
}
#Nullable
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = stock.getReadableDatabase();
int code = matcher.match(uri);
long id;
Cursor cursor;
switch (code)
{
case ID_STOCK_TABLE:
cursor = db.query(STOCK_TABLE, projection, selection,
selectionArgs, null, null, sortOrder);
break;
default:
Log.d("Uri provider =", uri.toString());
throw new UnsupportedOperationException("Pas encore implémenté");
}
return cursor;
}
#Nullable
#Override
public String getType(Uri uri) {
return null;
}
#Nullable
#Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = stock.getWritableDatabase();
int code = matcher.match(uri);
long id;
Uri.Builder builder = new Uri.Builder();
switch(code)
{
case ID_STOCK_TABLE:
System.out.println(values.toString());
id = db.insert(STOCK_TABLE, null, values);
builder.appendPath(STOCK_TABLE);
break;
default:
throw new UnsupportedOperationException("Pas encore implémenté");
}
builder.authority(authority);
builder = ContentUris.appendId(builder, id);
return builder.build();
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = stock.getWritableDatabase();
int code = matcher.match(uri);
int i;
switch(code)
{
case ID_STOCK_TABLE:
long id = ContentUris.parseId(uri);
i = db.delete(STOCK_TABLE, "_id=" + id, null);
break;
default:
throw new UnsupportedOperationException("Pas encore implémenté");
}
return 0;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
Thank you guys !
EDIT : I said rows instead of columns...
it's the first time I'm using the content provider.
so I have this:
public class ContactsContentProvider extends ContentProvider {
private ContactsDatabaseHelper dbHelper;
private static final UriMatcher uriMatcher =
new UriMatcher(UriMatcher.NO_MATCH);
private static final int ONE_CONTACT = 1;
private static final int CONTACTS = 2;
private static final int CONTACT = 3;
static {
uriMatcher.addURI(ContactsDatabaseDescription.AUTHORITY,
Contact.TABLE_NAME + "/#", ONE_CONTACT);
uriMatcher.addURI(ContactsDatabaseDescription.AUTHORITY,
Contact.TABLE_NAME, CONTACTS);
uriMatcher.addURI(ContactsDatabaseDescription.AUTHORITY,
Contact.TABLE_NAME + "/*" , CONTACT);
}
#Override
public boolean onCreate() {
dbHelper = new ContactsDatabaseHelper(getContext());
return true;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(Contact.TABLE_NAME);
switch (uriMatcher.match(uri)) {
case ONE_CONTACT:
queryBuilder.appendWhere(
Contact._ID + "=" + uri.getLastPathSegment());
break;
case CONTACTS:
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_query_uri) + uri);
}
Cursor cursor = queryBuilder.query(dbHelper.getReadableDatabase(),
projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// insert a new contact in the database
#Override
public Uri insert(Uri uri, ContentValues values) {
Uri newContactUri = null;
switch (uriMatcher.match(uri)) {
case CONTACTS:
// insert the new contact--success yields new contact's row id
long rowId = dbHelper.getWritableDatabase().insert(
Contact.TABLE_NAME, null, values);
if (rowId > 0) {
newContactUri = Contact.buildContactUri(rowId);
getContext().getContentResolver().notifyChange(uri, null);
}
else
throw new SQLException(
getContext().getString(R.string.insert_failed) + uri);
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_insert_uri) + uri);
}
return newContactUri;
}
#Override
public int update(Uri uri, ContentValues values,
String selection, String[] selectionArgs) {
int numberOfRowsUpdated; // 1 if update successful; 0 otherwise
switch (uriMatcher.match(uri)) {
case ONE_CONTACT:
String id = uri.getLastPathSegment();
numberOfRowsUpdated = dbHelper.getWritableDatabase().update(
Contact.TABLE_NAME, values, Contact._ID + "=" + id,
selectionArgs);
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_update_uri) + uri);
}
if (numberOfRowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return numberOfRowsUpdated;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int numberOfRowsDeleted;
switch (uriMatcher.match(uri)) {
case ONE_CONTACT:
String id = uri.getLastPathSegment();
numberOfRowsDeleted = dbHelper.getWritableDatabase().delete(
Contact.TABLE_NAME, Contact._ID + "=" + id, selectionArgs);
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_delete_uri) + uri);
}
if (numberOfRowsDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return numberOfRowsDeleted;
}
}
My database is
public class ContactsDatabaseDescription {
public static final String AUTHORITY =
"com.example.afran.bdcontacts.data";
private static final Uri BASE_CONTENT_URI =
Uri.parse("content://" + AUTHORITY);
public static final class Contact implements BaseColumns {
public static final String TABLE_NAME = "contacts"; // table's name
public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(TABLE_NAME).build();
public static final String COLUMN_FIRST_NAME = "firstName";
public static final String COLUMN_LAST_NAME = "lastName";
public static final String COLUMN_EMAIL = "email";
public static final String COLUMN_TYPE = "type";
public static Uri buildContactUri(long id) {
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
}
and on this fragment I read one last name (search) and I want to find the contact and I do not know how
public class DetailFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor> {
public interface DetailFragmentListener {
void onContactDeleted();
void onEditContact(Uri contactUri);
}
private static final int CONTACT_LOADER = 0;
private DetailFragmentListener listener;
private Uri contactUri;
private TextView prenomTextView;
private TextView nomTextView;
private TextView emailTextView;
private TextView typeTextView;
#Override
public void onAttach(Context context) {
super.onAttach(context);
listener = (DetailFragmentListener) context;
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
setHasOptionsMenu(true);
Bundle arguments = getArguments();
if (arguments != null)
contactUri = arguments.getParcelable(MainActivity.CONTACT_URI);
View view =
inflater.inflate(R.layout.fragment_detail, container, false);
prenomTextView = (TextView) view.findViewById(R.id.firstNameTextView);
nomTextView = (TextView) view.findViewById(R.id.lastNameTextView);
emailTextView = (TextView) view.findViewById(R.id.emailTextView);
typeTextView = (TextView) view.findViewById(R.id.typeTextView);
getLoaderManager().initLoader(CONTACT_LOADER, null, this);
return view;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_main, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit:
listener.onEditContact(contactUri);
return true;
case R.id.action_delete:
deleteContact();
return true;
case R.id.action_search:
searchContact();
return true;
}
return super.onOptionsItemSelected(item);
}
private void searchContact() {
final EditText input = new EditText(getContext());
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.menuitem_recherche);
builder.setMessage(R.string.label_lastName);
builder.setView(input);
builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int whichButton) {
String value = input.getText().toString();
return;
}
});
builder.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
return;
}
});
builder.create().show();
}
private void deleteContact() {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.confirm_title);
builder.setMessage(R.string.confirm_message);
builder.setPositiveButton(R.string.button_delete, new DialogInterface.OnClickListener() {
#Override
public void onClick(
DialogInterface dialog, int button) {
getActivity().getContentResolver().delete(
contactUri, null, null);
listener.onContactDeleted();
}
}
);
builder.setNegativeButton(R.string.button_cancel, null);
builder.create().show();
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader;
switch (id) {
case CONTACT_LOADER:
cursorLoader = new CursorLoader(getActivity(),
contactUri,
null,
null,
null,
null);
break;
default:
cursorLoader = null;
break;
}
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (data != null && data.moveToFirst()) {
int firstIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_FIRST_NAME);
int lastIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_LAST_NAME);
int emailIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_EMAIL);
int typeIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_TYPE);
prenomTextView.setText(data.getString(firstIndex));
nomTextView.setText(data.getString(lastIndex));
emailTextView.setText(data.getString(emailIndex));
typeTextView.setText(data.getString(typeIndex));
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) { }
}
It is simple to search for a match of any column in your table. You simply need the contentUri, and where and whereArgs parameters for the query. Ensure your Uri points to the whole table. Assuming you want to match columns called "first_name" and "surname" with Strings called firstName and surname.
String where = "first_name =? and surname =?";
String[] whereArgs = {firstName, surname};
You can use parentheses and "and" and "or" to construct more complex queries. With numerical fields you can use > and < etc. You must ensure whereArgs has as many elements as where has "?"
So I am trying to refresh a list fragment when an item is deleted. The way I have it right now restarts the loader which causes a stutter in the UI when the loader is actually restarting.
I am restarting the loader in the listViewLongClick() method.
Here is my code for the adapter and list fragment:
public class EntriesListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
private SimpleCursorAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_entries_list, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initButton();
fillData();
listViewLongClick()
}
private void listViewLongClick() { assignmentsListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, final View view, int i, long l) {
String entryId = ((TextView) view.findViewById(R.id.assignment_id)).getText().toString();
Uri uri = ElicitContract.Assignments.buildAssignmentIdUri(assignmentId);
mContentResolver.delete(uri, null, null);
getLoaderManager().restartLoader(0, null, AssignmentsListFragment.this);
fillData();
return true;
});
}
private void fillData() {
String[] from = new String[]{EntriesContract.EntriesColumns.ENTRIES_TITLE, EntriesContract.EntriesColumns.ENTRIES_DETAIL};
int[] to = new int[]{R.id.entries_title, R.id.entries_description};
getLoaderManager().initLoader(0, null, this);
adapter = new SimpleCursorAdapter(getActivity(), R.layout.custom_entries, null, from, to, 0);
setListAdapter(adapter);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = {EntriesContract.EntriesColumns.ENTRIES_ID, EntriesContract.EntriesColumns.ENTRIES_TITLE, EntriesContract.EntriesColumns.ENTRIES_DETAIL};
CursorLoader cursorLoader = new CursorLoader(getActivity(), EntriesContract.ENTRIES_BASE_CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
#Override
public void onResume() {
super.onResume();
fillData();
}
}
Here is my content provider code:
public class ElicitProvider extends ContentProvider {
private static final String TAG = ElicitProvider.class.getSimpleName();
private EntriesDatabase entriesDatabase; // Get a copy of the database.
private static final UriMatcher sUriMatcher = buildUriMatcher();
private static final int ENTRIES = 1;
private static final int ENTRIES_ID = 2;
private static UriMatcher buildUriMatcher() {
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = EntriesContract.CONTENT_AUTHORITY;
matcher.addURI(authority, "entries", ENTRIES);
matcher.addURI(authority, "entries/*", ENTRIES_ID);
return matcher;
}
#Override
public boolean onCreate() {
entriesDatabase = new EntriesDatabase(getContext()); // Creating a new instance of the Elicit Database.
return true;
}
#Override
public String getType(Uri uri) {
final int match = sUriMatcher.match(uri);
switch (match) {
case ENTRIES:
return EntriesContract.Entries.CONTENT_ENTRIES_TYPE;
case ENTRIES_ID:
return EntriesContract.Entries.CONTENT_ENTRIES_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown Uri: " + uri);
}
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
final SQLiteDatabase db = entriesDatabase.getReadableDatabase();
final int match = sUriMatcher.match(uri);
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(EntriesContract.ENTRIES_PATH);
switch (match) {
case ENTRIES:
break;
case ENTRIES_ID:
String id = EntriesContract.Entries.getEntryId(uri);
queryBuilder.appendWhere(BaseColumns._ID + "=" + id);
break;
default:
throw new IllegalArgumentException("Unknown Uri: " + uri);
}
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
return cursor;
}
#Override
public Uri insert(Uri uri, ContentValues contentValues) {
final SQLiteDatabase db = entriesDatabase.getWritableDatabase();
final int match = sUriMatcher.match(uri);
long recordId;
switch (match) {
case ENTRIES:
recordId = db.insertOrThrox(EntriesDatabase.Tables.ENTRIES, null, contentValues);
return EntriesContract.Entxies.buildentryIdUri(String.valueOf(recordId));
default:
throw new IllegalArgumentEception("Unknown Uri: " + uri);
}
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
if (uri.equals(EntriesContract.BASE_CONTENT_URI)) {
deleteDatabase();x
return 0;
}
final SQLiteDatabase db = entriesDatabase.getWritableDatabase();
final int match = sUriMatcher.match(uri);
switch (match) {
case ENTRIES_ID:
String id = uri.getLastPathSegment();
String selectionCriteria = BaseColumns._ID + "=" + id + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : "");
return db.delete(EntriesDatabase.Tables.ENTRIES, selectionCriteria, selectionArgs);
default:
throw new IllegalArgumentException("Unknown Uri: " + uri);
}
}
#Override
public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
final SQLiteDatabase db = entriesDatabase.getWritableDatabase();
final int match = sUriMatcher.match(uri);
String selectionCriteria = selection;
switch (match) {
case ENTRIES:
break;
case ENTRIES_ID:
String id = EntriesContract.Entries.getentryId(uri);
selectionCriteria = BaseColumns._ID + "=" + id + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : "");
break;
default:
throw new IllegalArgumentException("Unknown Uri: " + uri);
}
int updateCount = db.update(EntriesDatabase.Tables.ENTRIES, contentValues, selectionCriteria, selectionArgs);
return updateCount;
}
// Delete the instance of the database and create a new one
public void deleteDatabase() {
entriesDatabase.close();
EntriesDatabase.deleteDatabase(getContext());
entriesDatabase = new EntriesDatabase(getContext());
}
}
I am also thinking that this is not the most efficient method of refreshing a list fragment.
I took a look at other similar issues and they said to use entriesListView.notifyDataSetChanged() but I don't know where to put it and how to use it because if I replace this line with getLoaderManager().restartLoader then it gives me a null pointer error.
To summarize, my question is how would I dynamically refresh a listFragment without restarting the loader which I think is less efficient and causes a stutter in the UI.
Thank you to everyone in advance for helping me out!
I have followed the below tutorial http://www.vogella.de/articles/AndroidSQLite/article.htm
But getting this exception after clicking on "confirm" button
01-20 10:18:14.585: E/AndroidRuntime(2006): Caused by: java.lang.IllegalArgumentException: Unknown URL content://com.example.todos.contentprovider/todos
01-20 10:18:14.585: E/AndroidRuntime(2006): at android.content.ContentResolver.insert(ContentResolver.java:910)
01-20 10:18:14.585: E/AndroidRuntime(2006): at com.example.todos.TodoDetailActivity.saveState(TodoDetailActivity.java:122)
01-20 10:18:14.585: E/AndroidRuntime(2006): at com.example.todos.TodoDetailActivity.onPause(TodoDetailActivity.java:100)
TodoDetailActivity
public class TodoDetailActivity extends Activity {
private Spinner mCategory;
private EditText mTitleText;
private EditText mBodyText;
private Uri todoUri;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.todo_edit);
mCategory = (Spinner) findViewById(R.id.category);
mTitleText = (EditText) findViewById(R.id.todo_edit_summary);
mBodyText = (EditText) findViewById(R.id.todo_edit_description);
Button confirmButton = (Button) findViewById(R.id.todo_edit_button);
Bundle extras = getIntent().getExtras();
// check from the saved Instance
todoUri = (bundle == null) ? null : (Uri) bundle
.getParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE);
// Or passed from the other activity
if (extras != null) {
todoUri = extras
.getParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE);
fillData(todoUri);
}
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (TextUtils.isEmpty(mTitleText.getText().toString())) {
makeToast();
} else {
setResult(RESULT_OK);
finish();
}
}
});
}
private void fillData(Uri uri) {
String[] projection = { TodoTable.COLUMN_SUMMARY,
TodoTable.COLUMN_DESCRIPTION, TodoTable.COLUMN_CATEGORY };
Cursor cursor = getContentResolver().query(uri, projection, null, null,
null);
if (cursor != null) {
cursor.moveToFirst();
String category = cursor.getString(cursor
.getColumnIndexOrThrow(TodoTable.COLUMN_CATEGORY));
for (int i = 0; i < mCategory.getCount(); i++) {
String s = (String) mCategory.getItemAtPosition(i);
if (s.equalsIgnoreCase(category)) {
mCategory.setSelection(i);
}
}
mTitleText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(TodoTable.COLUMN_SUMMARY)));
mBodyText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(TodoTable.COLUMN_DESCRIPTION)));
// always close the cursor
cursor.close();
}
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putParcelable(MyTodoContentProvider.CONTENT_ITEM_TYPE, todoUri);
}
#Override
protected void onPause() {
super.onPause();
saveState();
}
private void saveState() {
String category = (String) mCategory.getSelectedItem();
String summary = mTitleText.getText().toString();
String description = mBodyText.getText().toString();
// only save if either summary or description
// is available
if (description.length() == 0 && summary.length() == 0) {
return;
}
ContentValues values = new ContentValues();
values.put(TodoTable.COLUMN_CATEGORY, category);
values.put(TodoTable.COLUMN_SUMMARY, summary);
values.put(TodoTable.COLUMN_DESCRIPTION, description);
if (todoUri == null) {
// New todo
todoUri = getContentResolver().insert(
MyTodoContentProvider.CONTENT_URI, values);
} else {
// Update todo
getContentResolver().update(todoUri, values, null, null);
}
}
private void makeToast() {
Toast.makeText(TodoDetailActivity.this, "Please maintain a summary",
Toast.LENGTH_LONG).show();
}
}
MyTodoContentProvider
public class MyTodoContentProvider extends ContentProvider{
//database
private TodoDatabaseHelper database;
//Used for the uriMatcher
private static final int TODOS = 10;
private static final int TODO_ID = 20;
private static final String AUTHORITY = "com.example.todos.contentprovider";
private static final String BASE_PATH = "todos";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY+ "/" + BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE +"/todos";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/todo";
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH, TODOS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", TODO_ID);
}
#Override
public boolean onCreate()
{
database = new TodoDatabaseHelper(getContext());
return false;
}
#Override
public Cursor query(Uri uri,String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
// Uisng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// check if the caller has requested a column which does not exists
checkColumns(projection);
//set the table
queryBuilder.setTables(TodoTable.TABLE_TODO);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TODOS:
break;
case TODO_ID:
// adding the ID to the original query
queryBuilder.appendWhere(TodoTable.COLUMN_ID + "="
+ uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
// make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values)
{
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
long id = 0;
switch (uriType) {
case TODOS:
id = sqlDB.insert(TodoTable.TABLE_TODO, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
#Override
public int delete(Uri uri, String selection,String[] selectionArgs)
{
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case TODOS:
rowsDeleted = sqlDB.delete(TodoTable.TABLE_TODO,selection, selectionArgs);
break;
case TODO_ID:
String id = uri.getLastPathSegment();
if(TextUtils.isEmpty(selection))
{
rowsDeleted = sqlDB.delete(TodoTable.TABLE_TODO,TodoTable.COLUMN_ID + "=" + id,null);
}
else
{
rowsDeleted = sqlDB.delete(TodoTable.TABLE_TODO,TodoTable.COLUMN_ID + "=" + id + "and" + selection ,selectionArgs);
}
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs)
{
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDb = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case TODOS:
rowsUpdated = sqlDb.update(TodoTable.TABLE_TODO, values, selection, selectionArgs);
break;
case TODO_ID:
String id = uri.getLastPathSegment();
if(TextUtils.isEmpty(selection))
{
rowsUpdated = sqlDb.update(TodoTable.TABLE_TODO, values, TodoTable.COLUMN_ID + "=" + id, null);
}
else
{
rowsUpdated = sqlDb.update(TodoTable.TABLE_TODO, values, TodoTable.COLUMN_ID + "=" + id + "and" + selection, selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection)
{
String[] available = {TodoTable.COLUMN_CATEGORY,TodoTable.COLUMN_SUMMARY,TodoTable.COLUMN_DESCRIPTION,TodoTable.COLUMN_ID};
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
if(projection != null)
{
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}
TodoDatabaseHelper
public class TodoDatabaseHelper extends SQLiteOpenHelper{
private static final String DATABASE_NAME = "todotable.db";
private static final int DATABASE_VERSION = 1;
public TodoDatabaseHelper(Context context)
{
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
//Method is called during creation of database
#Override
public void onCreate(SQLiteDatabase database)
{
TodoTable.onCreate(database);
}
// Method is called during an upgrade of the database,
// e.g. if you increase the database version
#Override
public void onUpgrade(SQLiteDatabase database, int oldVersion,
int newVersion) {
TodoTable.onUpgrade(database, oldVersion, newVersion);
}
}
You are using
private static final String AUTHORITY = "com.example.todos.contentprovider";
// It should same as you defined in manifest
So this
Caused by: java.lang.IllegalArgumentException: Unknown URL content://com.example.todos.contentprovider/todos
So make sure you define your ContentProvider with same authority in manifest.xml
<provider
android:authorities="com.example.todos.contentprovider"
android:name=".YOUR_ContentProvider" >
</provider>
Hope this will work for you.
Also ensure that you give android:exported="true" in manifest.xml, also ensure they are placed inside </application> not inside </activity>.
<provider
android:name="com.example.todos.contentprovider"
android:authorities="com.example.todos.contentprovider.MyTodoContentProvider"
android:exported="true">
</provider>