SQL Database error - android

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);
}
}

Related

Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference [duplicate]

This question already has answers here:
java.lang.NullPointerException: Attempt to invoke interface method 'boolean android.database.Cursor.moveToFirst()' on a null object reference [duplicate]
(1 answer)
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
I do have a problem that gives me a headache. I store some images of my city in the sqlite database via a custom content provider. However when I run my app I get a null cursor.
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference
at theo.testing.androidcustomloaders.fragments.MainActivityFragment.onActivityCreated(MainActivityFragment.java:74)
at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:2089)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1133)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1290)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1677)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:604)
at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1220)
at android.app.Activity.performStart(Activity.java:5992)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2358) 
at android.app.ActivityThread.access$800(ActivityThread.java:144) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5219) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693) 
That would mean the the info are not stored correctly or the Uri of my provider is somehow faulty. So.
MyCityContract
public class MyCityContract {
public static final String CONTENT_AUTHORITY = "theo.testing.customloaders";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final class MyCityEntry implements BaseColumns{
//table name
public static final String TABLE_MY_CITY = "my_city";
//columns
public static final String _ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_ICON = "icon";
// create content uri
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
.appendPath(TABLE_MY_CITY).build();
// create cursor of base type directory for multiple entries
public static final String CONTENT_DIR_TYPE =
ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + TABLE_MY_CITY;
// create cursor of base type item for single entry
public static final String CONTENT_ITEM_TYPE =
ContentResolver.CURSOR_ITEM_BASE_TYPE +"/" + CONTENT_AUTHORITY + "/" + TABLE_MY_CITY;
// for building URIs on insertion
public static Uri buildFlavorsUri(long id){
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
}
MyCityDbHelper
public class MyCityDbHelper extends SQLiteOpenHelper{
public static final String LOG_TAG = MyCityDbHelper.class.getSimpleName();
//name & version
public static final String DATABASE_NAME = "city.db";
public static final int DATABASE_VERSION = 4;
// Create the database
public MyCityDbHelper(Context context) {
super(context, DATABASE_NAME,null,DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
final String SQL_CREATE_MY_CITY_TABLE = "CREATE TABLE " +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "(" + MyCityContract.MyCityEntry._ID +
" INTEGER PRIMARY KEY AUTOINCREMENT, " +
MyCityContract.MyCityEntry.COLUMN_NAME + " TEXT NOT NULL, " +
MyCityContract.MyCityEntry.COLUMN_ICON + " INTEGER NOT NULL);";
sqLiteDatabase.execSQL(SQL_CREATE_MY_CITY_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " +
newVersion + ". OLD DATA WILL BE DESTROYED");
// Drop the table
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + MyCityContract.MyCityEntry.TABLE_MY_CITY);
sqLiteDatabase.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");
// re-create database
onCreate(sqLiteDatabase);
}
}
MyCityProvider
public class MyCityProvider extends ContentProvider {
private static final String LOG_TAG = MyCityProvider.class.getSimpleName();
private static final UriMatcher sUriMatcher = buildUriMatcher();
private MyCityDbHelper myCityDbHelper;
//Codes for UriMatcher
private static final int MY_CITY = 100;
private static final int MY_CITY_WITH_ID = 200;
private static UriMatcher buildUriMatcher(){
// Build a UriMatcher by adding a specific code to return based on a match
// It's common to use NO_MATCH as the code for this case.
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = MyCityContract.CONTENT_AUTHORITY;
//add code for each URI
matcher.addURI(authority,MyCityContract.MyCityEntry.TABLE_MY_CITY,MY_CITY);
matcher.addURI(authority,MyCityContract.MyCityEntry.TABLE_MY_CITY + "/#",MY_CITY_WITH_ID);
return matcher;
}
#Override
public boolean onCreate() {
myCityDbHelper = new MyCityDbHelper(getContext());
return true;
}
#Override
public String getType(Uri uri) {
final int match = sUriMatcher.match(uri);
switch (match){
case MY_CITY: {
return MyCityContract.MyCityEntry.CONTENT_DIR_TYPE;
}
case MY_CITY_WITH_ID:{
return MyCityContract.MyCityEntry.CONTENT_ITEM_TYPE;
}
default:{
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){
Cursor retCursor;
switch(sUriMatcher.match(uri)){
// All Flavors selected
case MY_CITY:{
retCursor = myCityDbHelper.getReadableDatabase().query(
MyCityContract.MyCityEntry.TABLE_MY_CITY,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
return retCursor;
}
// Individual flavor based on Id selected
case MY_CITY_WITH_ID:{
retCursor = myCityDbHelper.getReadableDatabase().query(
MyCityContract.MyCityEntry.TABLE_MY_CITY,
projection,
MyCityContract.MyCityEntry._ID + " = ?",
new String[] {String.valueOf(ContentUris.parseId(uri))},
null,
null,
sortOrder);
return retCursor;
}
default:{
// By default, we assume a bad URI
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
}
#Override
public Uri insert(Uri uri, ContentValues contentValues) {
final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
Uri returnUri;
switch (sUriMatcher.match(uri)){
case MY_CITY:
long _id = db.insert(MyCityContract.MyCityEntry.TABLE_MY_CITY,null,contentValues);
Log.d("id",String.valueOf(_id));
// insert unless it is already contained in the database
if(_id>0){
returnUri = MyCityContract.MyCityEntry.buildFlavorsUri(_id);
}else {
throw new android.database.SQLException("Failed to insert row into: " + uri);
}
break;
default: {
throw new UnsupportedOperationException("Unknown uri: " + uri );
}
}
getContext().getContentResolver().notifyChange(uri,null);
return returnUri;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int numDeleted;
switch(match){
case MY_CITY:
numDeleted = db.delete(
MyCityContract.MyCityEntry.TABLE_MY_CITY, selection, selectionArgs);
// reset _ID
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");
break;
case MY_CITY_WITH_ID:
numDeleted = db.delete(MyCityContract.MyCityEntry.TABLE_MY_CITY,
MyCityContract.MyCityEntry._ID + " = ?",
new String[]{String.valueOf(ContentUris.parseId(uri))});
// reset _ID
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
return numDeleted;
}
#Override
public int bulkInsert(Uri uri, ContentValues[] values){
final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
switch(match){
case MY_CITY:
// allows for multiple transactions
db.beginTransaction();
// keep track of successful inserts
int numInserted = 0;
try{
for(ContentValues value : values){
if (value == null){
throw new IllegalArgumentException("Cannot have null content values");
}
long _id = -1;
try{
_id = db.insertOrThrow(MyCityContract.MyCityEntry.TABLE_MY_CITY,
null, value);
}catch(SQLiteConstraintException e) {
Log.w(LOG_TAG, "Attempting to insert " +
value.getAsString(
MyCityContract.MyCityEntry.COLUMN_NAME)
+ " but value is already in database.");
}
if (_id != -1){
numInserted++;
}
}
if(numInserted > 0){
// If no errors, declare a successful transaction.
// database will not populate if this is not called
db.setTransactionSuccessful();
}
} finally {
// all transactions occur at once
db.endTransaction();
}
if (numInserted > 0){
// if there was successful insertion, notify the content resolver that there
// was a change
getContext().getContentResolver().notifyChange(uri, null);
}
return numInserted;
default:
return super.bulkInsert(uri, values);
}
}
#Override
public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs){
final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
int numUpdated = 0;
if (contentValues == null){
throw new IllegalArgumentException("Cannot have null content values");
}
switch(sUriMatcher.match(uri)){
case MY_CITY:{
numUpdated = db.update(MyCityContract.MyCityEntry.TABLE_MY_CITY,
contentValues,
selection,
selectionArgs);
break;
}
case MY_CITY_WITH_ID: {
numUpdated = db.update(MyCityContract.MyCityEntry.TABLE_MY_CITY,
contentValues,
MyCityContract.MyCityEntry._ID + " = ?",
new String[] {String.valueOf(ContentUris.parseId(uri))});
break;
}
default:{
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
if (numUpdated > 0){
getContext().getContentResolver().notifyChange(uri, null);
}
return numUpdated;
}
}
MainActivityFragment
public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
private static final String LOG_TAG = MainActivityFragment.class.getSimpleName();
private MyCityAdpapter myCityAdpapter;
private static final int CURSOR_LOADER_ID = 0;
private GridView mGridView;
MyCity[] mMyCity = {
new MyCity("Ancient Theatre - Larisa", R.drawable.larissa1),
new MyCity("Ancient Theatre - Larisa", R.drawable.larissa2),
new MyCity("Municipality park", R.drawable.larissa3),
new MyCity("Municipality park", R.drawable.larissa4),
new MyCity("Old trains",R.drawable.larissa5),
new MyCity("Old trains",R.drawable.larissa6),
new MyCity("Church",
R.drawable.larissa7),
new MyCity("Church",
R.drawable.larissa8),
new MyCity("Alcazar park",
R.drawable.larissa9),
new MyCity("Alcazar park",
R.drawable.larissa10),
new MyCity("AEL FC Arena",
R.drawable.larissa11),
new MyCity("AEL FC Arena",
R.drawable.larissa12),
new MyCity("Larissa Fair",
R.drawable.larissa13),
new MyCity("Larissa Fair",
R.drawable.larissa14),
new MyCity("Larissa Fair",
R.drawable.larissa15),
new MyCity("Larissa Fair",
R.drawable.larissa16)
};
public MainActivityFragment() {
// Required empty public constructor
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
Cursor c =
getActivity().getContentResolver().query(MyCityContract.MyCityEntry.CONTENT_URI,
new String[]{MyCityContract.MyCityEntry._ID},
null,
null,
null);
if (c.getCount() == 0){
insertData();
}
// initialize loader
getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// inflate fragment_main layout
final View rootView = inflater.inflate(R.layout.fragment_main_activity, container, false);
// initialize our FlavorAdapter
myCityAdpapter = new MyCityAdpapter(getActivity(), null, 0, CURSOR_LOADER_ID);
// initialize mGridView to the GridView in fragment_main.xml
mGridView = (GridView) rootView.findViewById(R.id.flavors_grid);
// set mGridView adapter to our CursorAdapter
mGridView.setAdapter(myCityAdpapter);
return rootView;
}
// insert data into database
public void insertData(){
ContentValues[] cityValuesArr = new ContentValues[mMyCity.length];
// Loop through static array of MyCity, add each to an instance of ContentValues
// in the array of ContentValues
for(int i = 0; i < mMyCity.length; i++){
cityValuesArr[i] = new ContentValues();
cityValuesArr[i].put(MyCityContract.MyCityEntry.COLUMN_ICON, mMyCity[i].image);
cityValuesArr[i].put(MyCityContract.MyCityEntry.COLUMN_NAME,
mMyCity[i].name);
}
// bulkInsert our ContentValues array
getActivity().getContentResolver().bulkInsert(MyCityContract.MyCityEntry.CONTENT_URI,
cityValuesArr);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args){
return new CursorLoader(getActivity(),
MyCityContract.MyCityEntry.CONTENT_URI,
null,
null,
null,
null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
myCityAdpapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader){
myCityAdpapter.swapCursor(null);
}
}
I read the Cursor inside the onCreateView(...) method of my Fragment
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
Cursor c =
getActivity().getContentResolver().query(MyCityContract.MyCityEntry.CONTENT_URI,
new String[]{MyCityContract.MyCityEntry._ID},
null,
null,
null);
if (c.getCount() == 0){
insertData();
}
// initialize loader
getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
super.onActivityCreated(savedInstanceState);
}
and this is where I am thrown the null Cursor exception.
Any ideas?
Thanks,
Theo.
EDIT
I changed this if condition from
if (c.getCount() == 0){
insertData();
}
to
if (c == null){
insertData();
}
and I am getting this exception!
Caused by: java.lang.IllegalArgumentException: Unknown URL content://theo.testing.customloaders/my_city
So there is be an error with provider. hmm...
I think you has a problem at using getActivity in onActivityCreated in your MainActivity Fragment
getActivity "might" return null if called from within onActivityCreated...especially during a configuration change like orientation change because the activity gets destroyed...
move that initialization to onAttach...
following link helped me to find out
getActivity return null in fragment onActivityCreated in some rooted device
Ok. I fixed it. All I did was changing my authority name from
theo.testing.customloaders
to
theo.testing.customloaders.app

How to Dynamically Refresh ListFragment when Item is Deleted while Using SimpleCursorAdapter

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!

How to fix content provider url not found in android Content provider?

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>

Loader returns no data, or an empty cursor

I've got two loaders, each of which loads data from a different content provider.
The fragment is supplied with the ID of a medication from the first content provider, and the first loader loads all of the information related to that medication. The second loader is supposed to query the second content provider for all of the alarms associated with that medication.
The first loader works just fine, and returns all of the correct data. However, the second loader appears to return a null cursor, even though I know for a fact that there is plenty of data in the table that should be relevant. I say "appears" because using getCount() on the data in in onLoadFinished for the second loader causes my app to crash, and the only reason I can think that this would occur is if the cursor were null.
Anyway, here's the code for my loaders. If you need, I can give you the code for anything else you want.
/**
* Initializes the loaders.
*/
#Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
CursorLoader loader = null;
long id = getArguments().getLong(ARG_MED_ID);
switch(loaderId) {
case 0: // MedList Loader
Log.d("MedManager", "Loading med data");
Uri singleUri = ContentUris.withAppendedId(MedProvider.CONTENT_URI, id);
String[] projection = { MedTable.MED_ID,
MedTable.MED_NAME,
MedTable.MED_DOSAGE,
MedTable.MED_DATE_FILLED,
MedTable.MED_DURATION };
loader = new CursorLoader(getActivity(), singleUri,
projection, null, null,
MedTable.MED_NAME + " COLLATE LOCALIZED ASC");
break;
case 1: // AlarmList Loader
Log.d("MedManager", "Theoretically loading alarm list");
Uri baseUri = AlarmProvider.CONTENT_URI;
// Create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
String[] alarmProjection = { DailyAlarmTable.ALARM_ID,
DailyAlarmTable.ALARM_MEDNUM,
DailyAlarmTable.ALARM_TIME };
String select = "((" + DailyAlarmTable.ALARM_MEDNUM + " NOTNULL) AND ("
+ DailyAlarmTable.ALARM_MEDNUM + " = " + id + "))";
loader = new CursorLoader(getActivity(), baseUri,
alarmProjection, select, null,
DailyAlarmTable.ALARM_TIMESTAMP + " ASC");
break;
}
return loader;
}
/**
* Customizes the various TextViews in the layout to match
* the values pulled from the MedTable, or swaps the alarm cursor
* into the adapter.
*/
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch(loader.getId()) {
case 0:
setUpMedDetails(data);
break;
case 1:
Log.d("MedManager", "Alarm finished loading");
/*
* these lines are commented out because their presence causes
* the app to crash.
*/
/*
boolean isEmpty = data.getCount() < 1;
if(isEmpty) {
Log.d("MedManager", "No results");
}
*/
mAdapter.swapCursor(data);
break;
}
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
if(arg0.getId() == 1) {
mAdapter.swapCursor(null);
}
}
EDIT: For completeness' sake, and because the possibility always exists that I'm simply a massive idiot overlooking something obvious, here's the code by which I add alarms into the table:
/**
* This function will turn the hour and day into an "HH:mm AM/PM" string,
* calculate the timestamp, and then inserts them into the table.
*/
#Override
public void onTimePicked(int hourOfDay, int minute) {
Log.d("MedManager", "onTimePicked triggered");
// Convert the hour and minute into a string
String alarmString = formatAlarmString(hourOfDay, minute);
// Convert the hour and minute into a timestamp
long alarmTimestamp = getAlarmTimestamp(hourOfDay, minute);
// Define the URI to receive the results of the insertion
Uri newUri = null;
// Define a contentValues object to contain the new Values
ContentValues mValues = new ContentValues();
// Add medId;
long medId = getIntent().getLongExtra(MedDetailFragment.ARG_MED_ID, 0);
mValues.put(DailyAlarmTable.ALARM_MEDNUM, medId);
// Add the timestamp
mValues.put(DailyAlarmTable.ALARM_TIMESTAMP, alarmTimestamp);
// Add the time string
mValues.put(DailyAlarmTable.ALARM_TIME, alarmString);
// Insert the new alarm
Toast.makeText(getApplicationContext(), "medNum = " + medId, Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(), "time = " + alarmString, Toast.LENGTH_SHORT).show();
newUri = getContentResolver().insert(AlarmProvider.CONTENT_URI, mValues);
String uriStr = newUri.toString();
Toast.makeText(getApplicationContext(), "Uri = " + uriStr, Toast.LENGTH_SHORT).show();
}
As requested, here's my AlarmProvider class.
package com.gmail.jfeingold35.medicationmanager.alarmprovider;
import java.util.Arrays;
import java.util.HashSet;
import com.gmail.jfeingold35.medicationmanager.database.AlarmDatabaseHelper;
import com.gmail.jfeingold35.medicationmanager.database.DailyAlarmTable;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
public class AlarmProvider extends ContentProvider {
// Database
private AlarmDatabaseHelper database;
// Used for the UriMatcher
private static final int ALARMS = 10;
private static final int ALARM_ID = 20;
private static final String AUTHORITY = "com.gmail.jfeingold35.medicationmanager.alarmprovider";
private static final String BASE_PATH = "medicationmanager";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/" + BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE
+ "/alarms";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE
+ "/alarm";
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(AUTHORITY, BASE_PATH, ALARMS);
sUriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", ALARM_ID);
}
#Override
public boolean onCreate() {
database = new AlarmDatabaseHelper(getContext());
return false;
}
/**
* Perform a query from the alarm database
*/
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Using SQLiteQueryBuilder instead of the query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Check if the caller requested a column which doesn't exist
checkColumns(projection);
// Set the table
queryBuilder.setTables(DailyAlarmTable.TABLE_ALARM);
int uriType = sUriMatcher.match(uri);
switch(uriType) {
case ALARMS:
break;
case ALARM_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(DailyAlarmTable.ALARM_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 null;
}
/**
* Delete from the alarm database
*/
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase db = database.getWritableDatabase();
int rowsDeleted = 0;
switch(uriType) {
case ALARMS:
rowsDeleted = db.delete(DailyAlarmTable.TABLE_ALARM, selection,
selectionArgs);
break;
case ALARM_ID:
String id = uri.getLastPathSegment();
if(TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(DailyAlarmTable.TABLE_ALARM,
DailyAlarmTable.ALARM_ID + "=" + id, null);
} else {
rowsDeleted = db.delete(DailyAlarmTable.TABLE_ALARM,
DailyAlarmTable.ALARM_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase db = database.getWritableDatabase();
long id = 0;
switch(uriType) {
case ALARMS:
id = db.insert(DailyAlarmTable.TABLE_ALARM, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = sUriMatcher.match(uri);
SQLiteDatabase db = database.getWritableDatabase();
int rowsUpdated = 0;
switch(uriType) {
case ALARMS:
rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
values,
selection,
selectionArgs);
break;
case ALARM_ID:
String id = uri.getLastPathSegment();
if(TextUtils.isEmpty(selection)) {
rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
values,
DailyAlarmTable.ALARM_ID + "=" + id,
null);
} else {
rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
values,
DailyAlarmTable.ALARM_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
/**
* Confirms that the columns the user requested exist.
* #param projection
*/
public void checkColumns(String[] projection) {
String[] available = { DailyAlarmTable.ALARM_ID,
DailyAlarmTable.ALARM_MEDNUM,
DailyAlarmTable.ALARM_TIMESTAMP,
DailyAlarmTable.ALARM_TIME };
if(projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
// Check if all columns which are requested are available
if(!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columsn in projection");
}
}
}
}
Oh oh, okay I found that you return null in your query method of AlarmProvider class :)). Let's return cursor for this
If the onLoadFinished() method passes you a null cursor, then that means that the ContentProvider's query() method has returned null. You need to fix your query() method so that it doesn't return null in this case.

Android Content Provider with multiple tables unknow uri error

I followed a tutorial about sqlite and content providers but it had only examples for a single table, I eventually managed to figure how to expand that provider to include two tables and everything seems to be working fine.
The app I'm trying to make as a self excercise has right now a todo mode and a notes mode, the classes are almost iedntical, the only difference is a few database column entries.
The todo mode (which was in the example) works perfectly, I can create new entries, view and delete them, while the notes mode can create and delete entries but for some bizarre reason it can't open them as it gives me an exception about the uri not being recognized.
This is the error I'm getting:
02-28 10:08:40.343: E/AndroidRuntime(20079): FATAL EXCEPTION: main
02-28 10:08:40.343: E/AndroidRuntime(20079): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jackomel.maddonote/com.jackomel.maddonote.NotesDetailActivity}: java.lang.IllegalArgumentException: Unknown URI: content://com.jackomel.maddonote.contentprovider/maddonote/1
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2304)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2354)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.access$600(ActivityThread.java:150)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1244)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.os.Handler.dispatchMessage(Handler.java:99)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.os.Looper.loop(Looper.java:137)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.main(ActivityThread.java:5191)
02-28 10:08:40.343: E/AndroidRuntime(20079): at java.lang.reflect.Method.invokeNative(Native Method)
02-28 10:08:40.343: E/AndroidRuntime(20079): at java.lang.reflect.Method.invoke(Method.java:511)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
02-28 10:08:40.343: E/AndroidRuntime(20079): at dalvik.system.NativeStart.main(Native Method)
02-28 10:08:40.343: E/AndroidRuntime(20079): Caused by: java.lang.IllegalArgumentException: Unknown URI: content://com.jackomel.maddonote.contentprovider/maddonote/1
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.jackomel.maddonote.contentprovider.MyTodoContentProvider.query(MyTodoContentProvider.java:103)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentProvider.query(ContentProvider.java:652)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentProvider$Transport.query(ContentProvider.java:189)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentResolver.query(ContentResolver.java:372)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.content.ContentResolver.query(ContentResolver.java:315)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.jackomel.maddonote.NotesDetailActivity.fillData(NotesDetailActivity.java:102)
02-28 10:08:40.343: E/AndroidRuntime(20079): at com.jackomel.maddonote.NotesDetailActivity.onCreate(NotesDetailActivity.java:56)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.Activity.performCreate(Activity.java:5104)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
02-28 10:08:40.343: E/AndroidRuntime(20079): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2258)
02-28 10:08:40.343: E/AndroidRuntime(20079): ... 11 more
This is the content provider I have right now (skipping posting all the imports)
public class MyMaddoContentProvider extends ContentProvider {
// Database
private MaddoDatabaseHelper database;
// Used for urlMacher
private static final int TODOS = 10;
private static final int TODO_ID = 20;
private static final int NOTES = 11;
private static final int NOTE_ID = 21;
private static final String AUTHORITY = "com.jackomel.maddonote.contentprovider";
private static final String BASE_PATH = "maddo";
//private static final String NOTE_PATH = "notes";
public static final Uri TODO_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH + "todo");
public static final Uri NOTE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH + "note");
public static final String CONTENT_TYPE_TODO = ContentResolver.CURSOR_DIR_BASE_TYPE + "/todos";
public static final String CONTENT_ITEM_TYPE_TODO = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/todo";
public static final String CONTENT_TYPE_NOTE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/notes";
public static final String CONTENT_ITEM_TYPE_NOTE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/note";
public static final String[] todoAvailable = { TodoTable.COLUMN_CATEGORY,
TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_DESCRIPTION,
TodoTable.COLUMN_ID };
public static final String[] noteAvailable = { NotesTable.COLUMN_CATEGORY,
NotesTable.COLUMN_SUMMARY, NotesTable.COLUMN_CONTENT, NotesTable.COLUMN_DATE,
TodoTable.COLUMN_ID
};
private static final UriMatcher sURIMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "todo", TODOS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "todo" + "/#", TODO_ID);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "note", NOTES);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "note" + "/#", NOTE_ID);
}
#Override
public boolean onCreate() {
database = new MaddoDatabaseHelper(getContext());
return false;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Using 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_NAME);
int uriType = sURIMatcher.match(uri);
checkColumns(projection, uriType);
switch (uriType) {
case TODOS:
queryBuilder.setTables(TodoTable.TABLE_NAME);
break;
case TODO_ID:
queryBuilder.setTables(TodoTable.TABLE_NAME);
// Adding the ID to the original query
queryBuilder.appendWhere(TodoTable.COLUMN_ID + "="
+ uri.getLastPathSegment());
break;
case NOTES:
queryBuilder.setTables(NotesTable.TABLE_NAME);
break;
case NOTE_ID:
queryBuilder.setTables(NotesTable.TABLE_NAME);
queryBuilder.appendWhere(NotesTable.COLUMN_ID + "=" + uri.getLastPathSegment());
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();
int rowsDeleted = 0;
long id = 0;
String curPath;
switch (uriType) {
case TODOS:
System.out.println("Inserimento in tabella TODOS");
id = sqlDB.insert(TodoTable.TABLE_NAME, null, values);
curPath = "todo";
break;
case NOTES:
System.out.println("Inserimento in tabella NOTES");
id = sqlDB.insert(NotesTable.TABLE_NAME, null, values);
curPath = "note";
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + curPath + "/" + id);
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
String id;
switch (uriType) {
case NOTES:
rowsDeleted = sqlDB.delete(NotesTable.TABLE_NAME, selection, selectionArgs);
break;
case NOTE_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(NotesTable.TABLE_NAME, NotesTable.COLUMN_ID + "=" + id, null);
} else {
rowsDeleted = sqlDB.delete(NotesTable.TABLE_NAME, NotesTable.COLUMN_ID + "=" +
id + " and " + selection, selectionArgs);
break;
}
case TODOS:
rowsDeleted = sqlDB.delete(TodoTable.TABLE_NAME, selection,
selectionArgs);
break;
case TODO_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(TodoTable.TABLE_NAME,
TodoTable.COLUMN_ID + "=" + id, null);
} else {
rowsDeleted = sqlDB.delete(TodoTable.TABLE_NAME,
TodoTable.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
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;
String id;
switch (uriType) {
case NOTES:
rowsUpdated = sqlDB.update(NotesTable.TABLE_NAME, values, selection, selectionArgs);
break;
case NOTE_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(NotesTable.TABLE_NAME, values,
NotesTable.COLUMN_ID + "=" + id, null);
} else {
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, values,
NotesTable.COLUMN_ID + "=" + id + " and " + selection, selectionArgs);
}
break;
case TODOS:
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, values, selection,
selectionArgs);
break;
case TODO_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, values,
TodoTable.COLUMN_ID + "=" + id, null);
} else {
rowsUpdated = sqlDB.update(TodoTable.TABLE_NAME, 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, int uriType) {
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(
Arrays.asList(projection));
HashSet<String> availableColumns = null;
switch (uriType) {
case TODOS: case TODO_ID:
availableColumns = new HashSet<String>(
Arrays.asList(todoAvailable));
break;
case NOTES: case NOTE_ID:
availableColumns = new HashSet<String>(
Arrays.asList(noteAvailable));
break;
}
// Check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException(
"Unknown columns in projection");
}
}
}
}
And these are the activities in which the error is caused (again skipping imports):
public class NotesOverviewActivity extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor>{
private static final int ACTIVITY_CREATE = 0;
private static final int ACTIVITY_EDIT = 1;
private static final int DELETE_ID = Menu.FIRST + 1;
// private Cursor cursor;
private SimpleCursorAdapter adapter;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notes_list);
this.getListView().setDividerHeight(2);
fillData();
registerForContextMenu(getListView());
}
// Create the menu based on the XML defintion
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.listmenu, menu);
return true;
}
// Reaction to the menu selection
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.insert:
createNote();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
Uri uri = Uri.parse(MyMaddoContentProvider.NOTE_URI + "/"
+ info.id);
getContentResolver().delete(uri, null, null);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
private void createNote() {
Intent i = new Intent(this, NotesDetailActivity.class);
startActivity(i);
}
// Opens the second activity if an entry is clicked
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(this, NotesDetailActivity.class);
Uri notesUri = Uri.parse(MyMaddoContentProvider.NOTE_URI + "/" + id);
i.putExtra(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE, notesUri);
startActivity(i);
}
private void fillData() {
// Fields from the database (projection)
// Must include the _id column for the adapter to work
String[] from = new String[] { NotesTable.COLUMN_SUMMARY };
// Fields on the UI to which we map
int[] to = new int[] { R.id.label };
getLoaderManager().initLoader(0, null, this);
adapter = new SimpleCursorAdapter(this, R.layout.notes_row, null, from,
to, 0);
setListAdapter(adapter);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
// Creates a new loader after the initLoader () call
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { NotesTable.COLUMN_ID, NotesTable.COLUMN_SUMMARY };
CursorLoader cursorLoader = new CursorLoader(this,
MyMaddoContentProvider.NOTE_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) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
}
the error seems to happen in the onListenClick method, right after it starts the notesDetailActivity, which I'm including below
public class NotesDetailActivity extends Activity {
private Spinner mCategory;
private EditText mTitleText;
private EditText mBodyText;
private EditText mDateText;
private Uri noteUri;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.notes_edit);
mCategory = (Spinner) findViewById(R.id.category);
mTitleText = (EditText) findViewById(R.id.todo_edit_summary);
mBodyText = (EditText) findViewById(R.id.todo_edit_description);
mDateText = (EditText)findViewById(R.id.date);
mDateText.setText(java.text.DateFormat.getTimeInstance().format(Calendar.getInstance().getTime()));
Button confirmButton = (Button) findViewById(R.id.todo_edit_button);
Bundle extras = getIntent().getExtras();
// Check from the saved Instance
noteUri = (bundle == null) ? null : (Uri) bundle
.getParcelable(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE);
// Or passed from the other activity
if (extras != null) {
noteUri = extras
.getParcelable(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE);
fillData(noteUri);
}
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (TextUtils.isEmpty(mTitleText.getText().toString())) {
makeToast();
} else {
setResult(RESULT_OK);
finish();
}
}
});
}
// Create the menu based on the XML defintion
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.detailsmenu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save:
saveData();
return true;
}
return super.onOptionsItemSelected(item);
}
public void saveData() {
if (TextUtils.isEmpty(mTitleText.getText().toString())) {
makeToast();
} else {
setResult(RESULT_OK);
finish();
}
}
private void fillData(Uri uri) {
String[] projection = { NotesTable.COLUMN_SUMMARY,
NotesTable.COLUMN_CONTENT, NotesTable.COLUMN_CATEGORY, NotesTable.COLUMN_DATE };
Cursor cursor = getContentResolver().query(uri, projection, null, null,
null);
if (cursor != null) {
cursor.moveToFirst();
String category = cursor.getString(cursor
.getColumnIndexOrThrow(NotesTable.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(NotesTable.COLUMN_SUMMARY)));
mBodyText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(NotesTable.COLUMN_CONTENT)));
mDateText.setText(cursor.getString(cursor
.getColumnIndexOrThrow(NotesTable.COLUMN_DATE)));
// Always close the cursor
cursor.close();
}
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putParcelable(MyMaddoContentProvider.CONTENT_ITEM_TYPE_NOTE, noteUri);
}
#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();
String date = 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(NotesTable.COLUMN_CATEGORY, category);
values.put(NotesTable.COLUMN_SUMMARY, summary);
values.put(NotesTable.COLUMN_CONTENT, description);
values.put(NotesTable.COLUMN_DATE, date);
if (noteUri == null) {
// New note
noteUri = getContentResolver().insert(
MyMaddoContentProvider.NOTE_URI, values);
} else {
// Update note
getContentResolver().update(noteUri, values, null, null);
}
}
private void makeToast() {
Toast.makeText(NotesDetailActivity.this, "Please maintain a summary",
Toast.LENGTH_LONG).show();
}
}
I'm obviously doing something wrong with the uri, still no idea exactly what, considering the todo part is almost exactly the same (save for variable names and database table of course) and doesn't give such errors.
What is the problem?
I have followed the same example.. Here is your fix--
change your authority name in both manifest and MyMaddoContentProvider class as follows:-
private static final String AUTHORITY = "com.jackomel.maddonote.contentprovide.MyMaddoContentProviderr";
and
android:name="com.jackomel.maddonote.contentprovider.MyMaddoContentProvider"
android:authorities="com.jackomel.maddonote.contentprovider.MyMaddoContentProvider"
It should probably work now.
I think I may have found a solution to this problem. I was having a similar problem except for my error was saying that I had invalid tables instead of URI's. I followed Jackomels example above for his set tables queries and was able to get my edit to work. His Uri's are set up differently than mine which I am thinking is what the error is about. He uses the same BASE_PATH for both tables but I think that each table needs to have a different "base path".
I have private static final String BASE_PATH = "todos" & private static final String DEVICE_PATH = "devices";
I am pasting my code below in case it helps someone else.
package com.cossioinsurance.rentalsafety.contentprovider2;
import java.util.Arrays;
import java.util.HashSet;
import com.cossioinsurance.rentalsafety.database.TodoDatabaseHelper;
import com.cossioinsurance.rentalsafety.database.NoteTable;
import com.cossioinsurance.rentalsafety.database.DeviceTable;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
public class MyNoteContentProvider extends ContentProvider{
// database
private TodoDatabaseHelper database;
// used for the UriMacher
private static final int TODOS = 10;
private static final int TODO_ID = 20;
private static final int DEVICES = 30;
private static final int DEVICE_ID = 40;
private static final String AUTHORITY = "com.cossioinsurance.rentalsafety.contentprovider2";
private static final String BASE_PATH = "todos";
private static final String DEVICE_PATH = "devices";
public static final Uri CONTENT_URI_TODOS = Uri.parse("content://" + AUTHORITY
+ "/" + BASE_PATH);
public static final Uri CONTENT_URI_DEVICES = Uri.parse("content://" + AUTHORITY
+ "/" + DEVICE_PATH);
public static final String CONTENT_TYPE_TODOS = ContentResolver.CURSOR_DIR_BASE_TYPE
+ "/todos";
public static final String CONTENT_TYPE_DEVICES = ContentResolver.CURSOR_DIR_BASE_TYPE
+ "/devices";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE
+ "/todo";
public static final String CONTENT_ITEM_TYPE2 = ContentResolver.CURSOR_ITEM_BASE_TYPE
+ "/device";
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH, TODOS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", TODO_ID);
sURIMatcher.addURI(AUTHORITY, DEVICE_PATH, DEVICES);
sURIMatcher.addURI(AUTHORITY, DEVICE_PATH + "/#", DEVICE_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
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TODOS:
queryBuilder.setTables(NoteTable.TABLE_TODO);
break;
case TODO_ID:
queryBuilder.setTables(NoteTable.TABLE_TODO);
// adding the ID to the original query
queryBuilder.appendWhere(NoteTable.COLUMN_ID + "="
+ uri.getLastPathSegment());
break;
case DEVICES:
queryBuilder.setTables(DeviceTable.TABLE_DEVICE);
break;
case DEVICE_ID:
queryBuilder.setTables(DeviceTable.TABLE_DEVICE);
// adding the ID to the original query
queryBuilder.appendWhere(DeviceTable.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();
int rowsDeleted = 0;
long id = 0;
switch (uriType) {
case TODOS:
id = sqlDB.insert(NoteTable.TABLE_TODO, null, values);
break;
case DEVICES:
id = sqlDB.insert(DeviceTable.TABLE_DEVICE, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
//Deleted Rows
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
String id = uri.getLastPathSegment();
switch (uriType) {
case TODOS:
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO, selection,
selectionArgs);
break;
case TODO_ID:
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO,
NoteTable.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO,
NoteTable.COLUMN_ID + "=" + id
+ " and " + selection,
selectionArgs);
}
break;
case DEVICES:
rowsDeleted = sqlDB.delete(DeviceTable.TABLE_DEVICE, selection,
selectionArgs);
break;
case DEVICE_ID:
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(DeviceTable.TABLE_DEVICE,
DeviceTable.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(NoteTable.TABLE_TODO,
DeviceTable.COLUMN_ID + "=" + id
+ " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
//Update Rows
#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(NoteTable.TABLE_TODO,
values,
selection,
selectionArgs);
break;
case TODO_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(NoteTable.TABLE_TODO,
values,
NoteTable.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(NoteTable.TABLE_TODO,
values,
NoteTable.COLUMN_ID + "=" + id
+ " and "
+ selection,
selectionArgs);
}
break;
case DEVICES:
rowsUpdated = sqlDB.update(DeviceTable.TABLE_DEVICE,
values,
selection,
selectionArgs);
break;
case DEVICE_ID:
id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(DeviceTable.TABLE_DEVICE,
values,
DeviceTable.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(DeviceTable.TABLE_DEVICE,
values,
DeviceTable.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 = { NoteTable.COLUMN_CATEGORY,
NoteTable.COLUMN_SUMMARY, NoteTable.COLUMN_DESCRIPTION, NoteTable.COLUMN_EMAIL, NoteTable.COLUMN_RENTALDATES,
NoteTable.COLUMN_ENDDATES, NoteTable.COLUMN_TIME, NoteTable.COLUMN_LOCATION, NoteTable.COLUMN_NOTES,
NoteTable.COLUMN_ID, DeviceTable.COLUMN_ID, DeviceTable.COLUMN_CATEGORY, DeviceTable.COLUMN_NAME, DeviceTable.COLUMN_TYPE };
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
// check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}

Categories

Resources