I have created a content uri from one app :
content://SendDataProvider/bookevent
i am able to insert the values into it.
like :
content://SendDataProvider/bookevent/1
content://SendDataProvider/bookevent/2 etc...
but when i call it to other app for geting all record from this URI i use
String bookContentDataLog = "content://SendDataProvider/bookevent";
Uri bookrecord = Uri.parse(bookContentDataLog);
Cursor cursor = BookShelfActivity.this.getContentResolver().query(
bookrecord, null, null, null, null);
if (cursor.moveToFirst()) { // I got Null pointer exception here
String sessionId = cursor.getString(cursor.getColumnIndex(BOOK_COLUMN_SESSIONID));
String magId = cursor.getString(cursor.getColumnIndex(BOOK_COLUMN_MAG_ID));
}
I debug it and i found that
BookShelfActivity.this.getContentResolver().query(
bookrecord, null, null, null, null);
this return null value to cursor.
How i get all value inserted to this "content://SendDataProvider/bookevent"?
============== I have Used method to insert to uri ===================
1) Class Name and variables
public class SendDataProvider extends ContentProvider {
public SendDataProvider(Context c) {
this.context = c;//getContext();
BookDb dbHelper = new BookDb(context);
db = dbHelper.getWritableDatabase();
}
2) content provider class methode :===
#Override
public Uri insert(Uri uri, ContentValues contentValues) throws NullPointerException {
Log.e("SendDataProvider #Override inserted call","Uri insert");
long rowID = db.insert(BOOK_TABLE_NAME, null, contentValues);
Log.e("SendDataProvider #Override inserted ID","Uri insert ID"+rowID);
if (rowID > 0) {
Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
this.context.getContentResolver().notifyChange(_uri, null);
return _uri;
}
throw new SQLException("Failed to add a record into " + uri);
}
3) query
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(BOOK_TABLE_NAME);
switch (uriMatcher.match(uri)) {
case uriCode:
qb.setProjectionMap(this.values);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (sortOrder == null || sortOrder == "") {
sortOrder = BOOK_COLUMN_MAG_ID;
}
Cursor c = qb.query(db, projection, selection, selectionArgs, null,
null, sortOrder);
c.setNotificationUri(this.context.getContentResolver(), uri);
return c;
}
SOLVED :
Step 1:
create Provider class with DB inser/update/delte/query and be carefull about this things.
static final String PROVIDER_NAME = "com.example.contentprovideruser.DataProvider";//"org.geometerplus.android.fbreader.interfaces.SendDataProvider";
static final String URL = "content://" + PROVIDER_NAME + "/bookevent";
static final Uri CONTENT_URI = Uri.parse(URL);
You need to create well URI
Step 2: Add PROVIDER_NAME AndroidManifest.xml
<provider android:name=".DataProvider"
android:authorities="com.example.contentprovideruser.DataProvider"
android:exported="true"
android:multiprocess="true">
</provider>
Step 3:Need to specify well MIME TYPE
#Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case BOOK:
return "vnd.android.cursor.dir/vnd.booktype";
case BOOK_ID:
return "vnd.android.cursor.item/vnd.booktype";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
step 4 :"CONTENT_URI" is your global uri where all value are inserted
you can use query to get result.
Uri students = DataProvider.CONTENT_URI;
Cursor c = getContentResolver().query(students, null, null, null, "name");
if (c.moveToFirst()) {
do{
Toast.makeText(this,
c.getString(c.getColumnIndex(DataProvider.BOOK_COLUMN_EVENT_NAME)) +
", " + c.getString(c.getColumnIndex( DataProvider.BOOK_COLUMN_FROMPAGE_NO)),
Toast.LENGTH_SHORT).show();
} while (c.moveToNext());
}
BE happy :)
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 am having some kind of weird problem with my content provider: selectionArgs refused to work for a particular column.
Insertion
void saveFile(File file, Cursor cursor, Context context) {
if (file.isDirectory()) {
throw new IllegalArgumentException(file.getName() + " must be a file");
}
values.put(IS_DIRECTORY, false);
// Some other values.put()
context.getContentResolver().insert(FolderContract.CONTENT_URI, values);
}
And
void saveFolder(File file, String filesNum, Context context, int directTracks) {
if (!file.isDirectory()) {
throw new IllegalArgumentException(file.getName() + " must be a directory");
}
ContentValues values = new ContentValues();
values.put(IS_DIRECTORY, true);
// Some other values.put()
context.getContentResolver().insert(FolderContract.CONTENT_URI, values);
}
My Query
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Timber.w("onCreateLoader: ");
String selection = String.format("%s = ? AND %s = ?", FolderContract.IS_DIRECTORY, FolderContract.PARENT_ID);
String[] selectionArgs = selectionArgs = new String[]{"0", args.getString(FOLDER_PATH)};
return new CursorLoader(getActivity(), FolderContract.CONTENT_URI, null, selection, selectionArgs, null);
}
I want the the query to return the rows with FolderContract.PARENT_ID column = args.getString(FOLDER_PATH) while the FolderContract.IS_DIRECTORY column will be false.
But the above query returns zero results however if I run it without the FolderContract.IS_DIRECTORY in the selection it returns all the matching
results.The weird thing is that if I loop through the cursor, some of the returned rows has its FolderContract.IS_DIRECTORY column as 0 while
others is 1.
ContentProvider
#Override
public Uri insert(#NonNull Uri uri, ContentValues values) {
final SQLiteDatabase database = dbHelper.getWritableDatabase();
long insertedRowId = database.insert(FolderContract.TABLE_NAME, null, values);
if (insertedRowId > -1) {
Uri insertedUri = ContentUris.withAppendedId(CONTENT_URI, insertedRowId);
getContext().getContentResolver().notifyChange(insertedUri, null);
return insertedUri;
}
database.close();
return uri;
}
#Override
public Cursor query(#NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
final SQLiteDatabase database = dbHelper.getReadableDatabase();
Cursor cursor = database.query(FolderContract.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
Please any idea what I am doing wrong?
I am struggling to get the update method working in my content provider, the update returns 0 and there is no updated information in the table. The table is populated at this point.
Here's the update function:
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = leagueDBHelper.getWritableDatabase();
int rowsUpdated = 0;
int uriType = uriMatcher.match(uri);
switch (uriType) {
case LEAGUES:
rowsUpdated = db.update(LeagueContract.LEAGUE_TABLE_NAME,
values, selection, selectionArgs);
break;
case LEAGUE_ID:
String newSelection = appendToSelection(uri, selection);
rowsUpdated = db.update(LeagueContract.LEAGUE_TABLE_NAME,
values, newSelection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unrecognised uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri,null);
return rowsUpdated;
}
private String appendToSelection(Uri uri, String selection) {
String id = uri.getLastPathSegment();
StringBuilder newSelection = new StringBuilder(LeagueContract.COLUMN_KEY_ID + "=" + id);
if (selection != null && !selection.isEmpty()) {
newSelection.append(" AND " + selection);
}
return newSelection.toString();
}
Here's where I call the update of the content provider:
message = "Player 1 wins";// we should get the name
ContentValues mUpdateValues = new ContentValues();
String[] projectionFields = new String[] {
LeagueContract.COLUMN_NAME_SCORE };
Uri uri = ContentUris.withAppendedId(LeagueContentProvider.LEAGUE_URI, player1Id);
ContentResolver content = getContentResolver();
Cursor cursor = content.query(uri, projectionFields, null, null, null);
cursor.moveToFirst();
int score = cursor.getInt(0);
score ++;
ContentValues values = new ContentValues();
values.put(LeagueContract.COLUMN_NAME_SCORE,score);
content.update(uri,values,null,null);
Connect to your DB with the remote shell and try to update manually.
Also you can add log messages in your content provider to trace values.
I would like to write a ContentObserver for my app's local table. Also I have ContentProvider to access the table. Now in one of my Activity i have to observe for a change in only one row of that table. I have the primary key to observe for it but the primary key is a TEXT not INTEGER. When googled on it I found about getting specific row's Uri by using ContentUris.withAppendedId method. But it requires id must be long(NUMBER). So is there a way I can get Uri of single row of a table when the id is TEXT?
From the comments of #pskink I found the way to achieve it and would like to share it. In the existing content provider's uri matcher we have to add '/*' with new entry as follows...
private static final String AUTH = "com.test.Provider";
public static final Uri TABLE_URI = Uri.parse("content://" + AUTH + "/"
+ TABLE_NAME);
public static final Uri TABLE_ID_URI = Uri.parse("content://" + AUTH
+ "/" + TABLE_NAME + "/*");
final static int TABLE_COMMENT = 10;
final static int TABLE_ROW_COMMENT = 11;
uriMatcher.addURI(AUTH, TABLE_NAME, TABLE_COMMENT);
uriMatcher.addURI(AUTH, TABLE_NAME + "/*", TABLE_ROW_COMMENT);
And in the query method as follows...
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String orderBy) {
db = dbManager.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case TABLE_COMMENT:
cursor = db.query(TABLE_NAME, projection, selection,selectionArgs, null, null, orderBy);
if (cursor != null)
cursor.setNotificationUri(getContext().getContentResolver(),uri);
break;
case TABLE_ROW_COMMENT:
String id = uri.getLastPathSegment();//getting the PK
cursor = db.query(TABLE_NAME, projection,Table._ID + "=?", new String[] { id },null, null, orderBy);
if (cursor != null)
cursor.setNotificationUri(getContext().getContentResolver(),uri);
break;
}
return cursor;
}
And from the activity or fragment can get a specific row's uri from the loader as follows...
Uri uri = Uri.withAppendedPath(Provider.TABLE_URI,
"pk value");
Cursor cursor = getContentResolver().query(uri, null, null, null,
null);
And in my case I'll use this Uri for Observer.
I have looked at this for a couple of days now and I completely can't work out why my content provider return 0 using the arguments I am passing it.
Here's my contentResolver code:
String[] expenditureProjection = {
BusinessOpsDatabase.COL_EXPEND_CAT_ID,
BusinessOpsDatabase.COL_EXPEND_DATE,
BusinessOpsDatabase.COL_EXPEND_AMOUNT,
BusinessOpsDatabase.COL_EXPEND_DESC,
BusinessOpsDatabase.COL_STERLING_EXCHANGE,
BusinessOpsDatabase.COL_COMPANY_ID,
BusinessOpsDatabase.CURRENCY_ID,
BusinessOpsDatabase.COL_MOD_DATE
};
// Defines a string to contain the selection clause
String selectionClause = null;
// An array to contain selection arguments
String[] selectionArgs = {expend_id.trim()};
selectionClause = BusinessOpsExpenditureProvider.EXPENDITURE_ID + "=?";
Log.d(TAG, expend_id+" Selected from list.");
Cursor expendCursor = getContentResolver().query(
BusinessOpsExpenditureProvider.CONTENT_URI, expenditureProjection, selectionClause, selectionArgs, null);
if (null == expendCursor) {
Log.d(TAG, "Expenditure cursor: Is null");
} else if (expendCursor.getCount() < 1) {
Log.d(TAG,"Expenditure cursor: Search was unsuccessful: "+expendCursor.getCount());
} else {
Log.d(TAG,"Expenditure cursor: Contains results");
int i=0;
expendCursor.moveToFirst();
// loop through cursor and populate country array
while (expendCursor.isAfterLast() == false)
{
expend_date_edit.setText(expendCursor.getString(1));
expend_amount_edit.setText(expendCursor.getString(3));
expend_desc_edit.setText(expendCursor.getString(4));
i++;
expendCursor.moveToNext();
}
}
Here's my content provider query method:
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = mDB.getWritableDatabase();
// A convenience class to help build the query
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(BusinessOpsDatabase.TABLE_EXPENDITURE);
switch (sURIMatcher.match(uri)) {
case EXPENDITURE:
if(selection != null && selectionArgs != null){
//values.get("company_contact");
String segment = uri.getLastPathSegment();
Log.d(TAG, "Last path segment: "+ segment);
String whereClause = BusinessOpsDatabase.EXPENDITURE_ID + "="+ selectionArgs[0];
Log.d(TAG, "Where clause: "+whereClause);
}
break;
case EXPENDITURE_ID:
// If this is a request for an individual status, limit the result set to that ID
qb.appendWhere(BusinessOpsDatabase.EXPENDITURE_ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
// Query the underlying database
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, null);
// Notify the context's ContentResolver if the cursor result set changes
c.setNotificationUri(getContext().getContentResolver(), uri);
// Return the cursor to the result set
return c;
}
I'm printing the whereclause to the log and I see '_id=3' which should be fine because I have pulled off a copy of my SQLite database and I can see that the expenditure table has an _id 3 row in it. Any Ideas?
What an epic problem this has been. I found the error in my ContentResolver code.
selectionClause = BusinessOpsExpenditureProvider.EXPENDITURE_ID + "=?";
I was using the EXPENDITURE_ID variable from the provider rather than the database class. The line now reads.
selectionClause = BusinessOpsDatabase.EXPENDITURE_ID + "=?";
And works!