unsupported uri when accessing content provider - android

EDIT
I get a java.lang.IllegalArgumentException: Unsupported URI: content://com.example.locationreminder.remindercontentprovider/items
Shouldn't I be able to pick whatever name I want for the AUTHORITY string? as well as the content URI?
I have the following code:
public class ReminderContentProvider extends ContentProvider {
private DatabaseHelper mDbHelper;
public static final String AUTHORITY = "com.example.locationreminder.remindercontentprovider";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/items");
public static final String TABLE_NAME = "reminder";
private static final int ALLROWS = 1;
private static final int SINGLE_ROW = 2;
public static interface ReminderColumns extends BaseColumns {
public static final Uri CONTENT_URI = ReminderContentProvider.CONTENT_URI;
public static final String TITLE = "Title";
public static final String DATE = "Date";
public static final String CONTENT_PATH = "items";
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.locationreminder.items";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.locationreminder.items";
}
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(AUTHORITY, ReminderColumns.CONTENT_PATH, ALLROWS);
sUriMatcher.addURI(AUTHORITY, ReminderColumns.CONTENT_PATH + "/#", SINGLE_ROW);
}
#Override
public boolean onCreate() {
mDbHelper = new DatabaseHelper(getContext());
return true;
}
#Override
public String getType(Uri uri) {
switch(sUriMatcher.match(uri)) {
case ALLROWS:
return ReminderColumns.CONTENT_TYPE;
case SINGLE_ROW:
return ReminderColumns.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(DatabaseHelper.REMINDER_TABLE_NAME);
switch (sUriMatcher.match(uri)) {
case ALLROWS:
// all nice and well
break;
case SINGLE_ROW:
// limit query to one row at most:
builder.appendWhere(ReminderColumns._ID + " = " + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
Cursor cursor = builder.query(mDbHelper.getWritableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
// if we want to be notified of any changes:
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
Note: I also implemented insert(), update() and delete() which aren't relevant for the error I get.
The manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.locationreminder"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<provider
android:name="com.example.locationreminder.ReminderContentProvider"
android:authorities="com.example.locationreminder.remindercontentprovider"
android:singleUser="false" /> <!-- other users can't use this provider -->
<activity
android:name="com.example.locationreminder.MainActivity"
android:theme="#android:style/Theme.Holo.Light"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.locationreminder.NewReminderActivity"
android:label="#string/title_activity_new_reminder"
android:theme="#style/CalendarTheme.WithActionBar" >
</activity>
</application>
EDIT
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(android.R.style.Theme_Holo_Light);
setContentView(R.layout.activity_main);
Cursor cursor = managedQuery(ReminderContentProvider.CONTENT_URI, null, null, null, null);
mSimpleCursorAdapter = new SpecialAdapter(this,
R.layout.row,
cursor,
new String[]{ DatabaseHelper.KEY_ID, DatabaseHelper.KEY_TITLE, DatabaseHelper.KEY_DATE }
new int[] { R.id.titleID, R.id.dateTimeOrLocationID },
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
getLoaderManager().initLoader(0, null, this);
ListView listView = (ListView) findViewById(R.id.list);
listView.setAdapter(mSimpleCursorAdapter);
}

Does the error happen when switch (sUriMatcher.match(uri)) falls to default case?
If so, then you need to pass uri that matches ALLROWS or SINGLE_ROW

Related

Got Unknown URL content in Android

I am new to Android. I wanted to practice my knowledge about Content Provide, but my app somehow crush and tell me there is an unknown URL content. I try to search for solution but still can't fix the problem...
The logcat message:
2020-05-25 20:10:24.547 15120-15120/com.example.punchinandout E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.punchinandout, PID: 15120
java.lang.IllegalArgumentException: Unknown URL content://com.example.punchinandout.data/time
at android.content.ContentResolver.insert(ContentResolver.java:1535)
at com.example.punchinandout.MainActivity$1.onClick(MainActivity.java:65)
at android.view.View.performClick(View.java:6256)
at android.view.View$PerformClick.run(View.java:24701)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
My provider in Mainifest:
<provider
android:authorities="com.example.punchinandout"
android:name=".data.TimeProvider"
android:exported="false"/>
My Content Provider class:
package com.example.punchinandout.data;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
import com.example.punchinandout.data.TimeContract.TimeEntry;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class TimeProvider extends ContentProvider {
private static final String TAG = TimeProvider.class.toString();
private static final int TIME = 100;
private static final int TIME_ID = 101;
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//Determine which content URI we have.
static{
sUriMatcher.addURI(TimeContract.CONTENT_AUTHORITY, TimeContract.CONTENT_PATH, TIME);
sUriMatcher.addURI(TimeContract.CONTENT_AUTHORITY, TimeContract.CONTENT_PATH, TIME_ID);
}
private TimeHelper mDbHelper;
#Override
public boolean onCreate() {
mDbHelper = new TimeHelper(getContext());
return true;
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, #Nullable String selection, #Nullable String[] selectionArgs, #Nullable String sortOrder) {
SQLiteDatabase database = mDbHelper.getReadableDatabase();
Cursor cursor;
int match = sUriMatcher.match(uri);
switch (match){
case TIME:
cursor = database.query(TimeEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break;
case TIME_ID:
selection = TimeEntry._ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
cursor = database.query(TimeEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("Cannot query with unknown URI: " + uri);
}
cursor.setNotificationUri(getContext().getContentResolver(), uri); //Set notification URI on cursor, so that the cursor will update when the URI is updated.
return cursor;
}
#Nullable
#Override
public Uri insert(#NonNull Uri uri, #Nullable ContentValues values) {
int match = sUriMatcher.match(uri);
switch (match){
case TIME:
return insertTimeRecord(uri, values);
default:
throw new IllegalArgumentException("Insertion is no support for " + uri);
}
}
private Uri insertTimeRecord(Uri uri, ContentValues values){
//Sanity check
if (values.containsKey(TimeEntry.COLUMN_RECORD)){
String time_record = values.getAsString(TimeEntry.COLUMN_RECORD);
if (time_record == null){
throw new IllegalArgumentException("Time record cannot be empty.");
}
}
//If there are no values to update, then don't try to update the database.
if (values.size() == 0){
return null;
}
SQLiteDatabase database = mDbHelper.getWritableDatabase();
long newRowId = database.insert(TimeEntry.TABLE_NAME, null, values);
//Check if the insertion is success.
if (newRowId == -1){
Log.e(TAG, "Insertion fail with " + uri);
return null;
}
getContext().getContentResolver().notifyChange(uri, null); //Notify all listener the data has changed
return ContentUris.withAppendedId(uri, newRowId);
}
#Override
public int update(#NonNull Uri uri, #Nullable ContentValues values, #Nullable String selection, #Nullable String[] selectionArgs) {
int match = sUriMatcher.match(uri);
switch (match){
case TIME:
return updateTimeRecord(uri, values, selection, selectionArgs);
case TIME_ID:
selection = TimeEntry._ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
return updateTimeRecord(uri, values, selection, selectionArgs);
default:
throw new IllegalArgumentException("Update fail with " + uri);
}
}
private int updateTimeRecord(Uri uri, ContentValues values, String selection, String[] selectionArgs){
//Sanity check
if (values.containsKey(TimeEntry.COLUMN_RECORD)){
String time_record = values.getAsString(TimeEntry.COLUMN_RECORD);
if (time_record == null){
return 0; //If the data is not inputted, update nothing in database.
}
}
//If there are no values to update, then don't try to update the database.
if (values.size() == 0){
return 0;
}
SQLiteDatabase database = mDbHelper.getWritableDatabase();
int rowUpdated = database.update(TimeEntry.TABLE_NAME, values, selection, selectionArgs);
if (rowUpdated != 0){
getContext().getContentResolver().notifyChange(uri, null); //Notify all listener the data has changed
}
return rowUpdated;
}
#Override
public int delete(#NonNull Uri uri, #Nullable String selection, #Nullable String[] selectionArgs) {
int match = sUriMatcher.match(uri);
switch (match){
case TIME:
return deleteTimeRecord(uri, selection, selectionArgs);
case TIME_ID:
selection = TimeEntry._ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
return deleteTimeRecord(uri, selection, selectionArgs);
default:
throw new IllegalArgumentException("Delete fail with " + uri);
}
}
private int deleteTimeRecord(Uri uri, String selection, String[] selectionArgs){
SQLiteDatabase database = mDbHelper.getWritableDatabase();
int rowDelected = database.delete(TimeEntry.TABLE_NAME, selection, selectionArgs);
if (rowDelected != 0){
getContext().getContentResolver().notifyChange(uri, null); //Notify all listener the data has changed
}
return rowDelected;
}
#Nullable
#Override
public String getType(#NonNull Uri uri) {
int match = sUriMatcher.match(uri);
switch (match){
case TIME:
return TimeEntry.CONTENT_LIST_TYPE;
case TIME_ID:
return TimeEntry.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri + " with match " + match);
}
}
}
My Contract class:
package com.example.punchinandout.data;
import android.content.ContentResolver;
import android.net.Uri;
import android.provider.BaseColumns;
public class TimeContract {
private TimeContract(){};
public static final String CONTENT_AUTHORITY = "com.example.punchinandout.data";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final String CONTENT_PATH = "time";
public static final class TimeEntry implements BaseColumns {
public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH);
//MIME type of all records.
public static final String CONTENT_LIST_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + CONTENT_PATH;
//MIME type of single record.
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + CONTENT_PATH;
public static final String TABLE_NAME = "time";
public static final String _ID = BaseColumns._ID;
public static final String COLUMN_RECORD = "record";
}
}
Can someone help me? :(
I have fixed the problem!!
My provider in Mainifest is that:
<provider
android:authorities="com.example.punchinandout"
android:name=".data.TimeProvider"
android:exported="false"/>
And I change to :
<provider
android:authorities="com.example.punchinandout.data"
android:name=".data.TimeProvider"
android:exported="false"/>
Let the authorities be the same as the authority in Contract class and the problem is fixed!
Sorry for not placed the Mainifest in the question at first time as I had no idea where the problem in my app before.

Getting "Failed to find provider info for ContentProvider" error

I'm creating a simple ContentProvider to access the data in my SQLite3 database. Although I've declared the provider in my AndroidManifest.xml file I'm getting "Failed to find provider info for
com.tur_cirdictionary.turkishcircassiandictionary".
What is the problem here?
Here is my AndroidManifest.xml and ContentProvider files.
This is the Github link for the project if needed.
//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tur_cirdictionary.turkish_circassiandictionary">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".ArchiveActivity"></activity>
<activity android:name=".Searchable">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value=".Searchable" />
</activity>
<provider
android:name="com.tur_cirdictionary.turkish_circassiandictionary.data.WordProvider"
android:authorities=
"com.tur_cirdictionary.turkish_circassiandictionary"
android:exported="false" />
</application>
//WordProvider.java
package com.tur_cirdictionary.turkish_circassiandictionary.data;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import static com.tur_cirdictionary.turkish_circassiandictionary.data.WordContract.BASE_CONTENT_URI;
import static com.tur_cirdictionary.turkish_circassiandictionary.data.WordContract.WordEntry;
public class WordProvider extends ContentProvider {
public static final String LOG_TAG = WordProvider.class.getSimpleName();
private static final int WORDS = 100;
private static final int WORD_ID = 101;
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sUriMatcher.addURI(WordContract.CONTENT_AUTHORITY, WordContract.PATH_WORDS, WORDS);
sUriMatcher.addURI(WordContract.CONTENT_AUTHORITY, WordContract.PATH_WORDS
+ "/#", WORD_ID);
}
private WordDbHelper wordDbHelper;
#Override
public boolean onCreate() {
wordDbHelper = new WordDbHelper(getContext());
return true;
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, #Nullable String selection,
#Nullable String[] selectionArgs, #Nullable String sortOrder) {
SQLiteDatabase database = wordDbHelper.getReadableDatabase();
Cursor cursor;
int match = sUriMatcher.match(uri);
switch (match) {
case WORDS:
cursor = database.query(WordEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
case WORD_ID:
selection = WordEntry._ID + "=?";
selectionArgs = new String[] {String.valueOf(ContentUris.parseId(uri))};
cursor = database.query(WordEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
default:
throw new IllegalArgumentException("Cannot query unknown URI " + uri);
}
return cursor;
}
#Nullable
#Override
public String getType(#NonNull Uri uri) {
int match = sUriMatcher.match(uri);
switch (match) {
case WORDS:
return WordEntry.CONTENT_LIST_TYPE;
case WORD_ID:
return WordEntry.CONTENT_ITEM_TYPE;
default:
throw new IllegalStateException("Unknown URI " + uri + " with match" + match);
}
}
#Nullable
#Override
public Uri insert(#NonNull Uri uri, #Nullable ContentValues values) {
int match = sUriMatcher.match(uri);
switch (match) {
case WORDS:
return insertWord(uri, values);
default:
throw new IllegalArgumentException("Insertion is not supported for " + uri);
}
}
#Override
public int delete(#NonNull Uri uri, #Nullable String selection,
#Nullable String[] selectionArgs) {
int match = sUriMatcher.match(uri);
SQLiteDatabase database = wordDbHelper.getWritableDatabase();
switch (match) {
case WORDS:
return database.delete(WordEntry.TABLE_NAME, selection, selectionArgs);
case WORD_ID:
long wordId = ContentUris.parseId(uri);
selection = WordEntry._ID + "=?";
selectionArgs = new String[] {String.valueOf(wordId)};
return database.delete(WordEntry.TABLE_NAME, selection, selectionArgs);
default:
throw new IllegalArgumentException("Delete is not supported for " + uri);
}
}
#Override
public int update(#NonNull Uri uri, #Nullable ContentValues values, #Nullable String selection, #Nullable String[] selectionArgs) {
int match = sUriMatcher.match(uri);
switch (match) {
case WORDS:
return updateWord(uri, values, selection, selectionArgs);
case WORD_ID:
long wordId = ContentUris.parseId(uri);
selection = WordEntry._ID + "=?";
selectionArgs = new String[] {String.valueOf(wordId)};
return updateWord(uri, values, selection, selectionArgs);
default:
throw new IllegalArgumentException("Update is not supported for " + uri);
}
}
private Uri insertWord(Uri uri, ContentValues values) {
if (values.containsKey(WordEntry.COLUMN_NAME_CIRCASSIAN)) {
String circassian = values.getAsString(WordEntry.COLUMN_NAME_TURKISH);
if (circassian == null) {
throw new IllegalArgumentException("Word requires circassian translation");
}
}
if (values.containsKey(WordEntry.COLUMN_NAME_TURKISH)) {
String turkish = values.getAsString(WordEntry.COLUMN_NAME_TURKISH);
if (turkish == null) {
throw new IllegalArgumentException("Word requires turkish translation");
}
}
if (values.size() > 0) {
return null;
}
SQLiteDatabase database = wordDbHelper.getWritableDatabase();
long idOfNewlyInserted = database.insert(WordEntry.TABLE_NAME, null, values);
if (idOfNewlyInserted == -1) {
Log.e(LOG_TAG, "Failed to insert row for: " + uri);
return null;
}
return ContentUris.withAppendedId(BASE_CONTENT_URI, idOfNewlyInserted);
}
private int updateWord(Uri uri, ContentValues values,
String selection, String[] selectionArgs) {
if (values.containsKey(WordEntry.COLUMN_NAME_CIRCASSIAN)) {
String circassian = values.getAsString(WordEntry.COLUMN_NAME_CIRCASSIAN);
if (circassian == null) {
throw new IllegalArgumentException("Circassian translation required ");
}
}
if (values.containsKey(WordEntry.COLUMN_NAME_TURKISH)) {
String turkish = values.getAsString(WordEntry.COLUMN_NAME_TURKISH);
if (turkish == null) {
throw new IllegalArgumentException("Turkish translation required");
}
}
if (values.size() < 0) {
return 0;
}
SQLiteDatabase database = wordDbHelper.getWritableDatabase();
return database.update(WordEntry.TABLE_NAME, values, selection, selectionArgs);
}
}
I've changed the CONTENT_AUTHORITY String to the
com.tur_cirdictionary.turkish_circassiandictionary
making it same with the package name. That solved the problem.

ContentProvider: cursor object null when trying to acces data with ContentResolver

I'm trying to share some data between my apps using ContentProvider. I have a problem with accessing the data with resolver in the second app: Cursor object is null after query. Can't figure out where I made a mistake in the code so I'm asking for help. Code of the first app which provides the data :
Provider in manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.piotr.planer">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BroadcastEvent" />
<provider
android:authorities="com.example.piotr.planer.PlansProvider"
android:name=".PlansProvider"
android:exported="true"
android:multiprocess="true" >
</provider>
</application>
Provider class:
package com.example.piotr.planer;
public class PlansProvider extends ContentProvider {
// Unique namespace for provider
static final String PROVIDER_NAME = "com.example.piotr.planer.PlansProvider";
static final String URL = "content://" + PROVIDER_NAME + "/cpplans";
static final Uri CONTENT_URL = Uri.parse(URL);
// Defining columns in database
static final String id = "id";
static final String name = "name";
static final String date = "date";
static final int uriCode = 1;
private static HashMap<String, String> values;
// UriMatcher matches our unique Uris with our ContentProviders
static final UriMatcher uriMatcher;
// assigning these unique Uris
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "cpplans", uriCode);
}
// Defining database
private SQLiteDatabase sqlDB;
static final String DATABASE_NAME = "myPlans";
static final String TABLE_NAME = "plans";
static final int DATABASE_VERSION = 1;
static final String CREATE_DB_TABLE = "CREATE TABLE " + TABLE_NAME +
" (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
" name TEXT NOT NULL, " +
" date INTEGER);";
#Override
public boolean onCreate() {
// Creates Database
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
sqlDB = dbHelper.getWritableDatabase();
if (sqlDB != null) {
return true;
}
return false;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(TABLE_NAME);
switch (uriMatcher.match(uri)) {
case uriCode:
queryBuilder.setProjectionMap(values);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
Cursor cursor = queryBuilder.query(sqlDB, projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case uriCode:
return "vnd.android.cursor.dir/cpplans";
default:
throw new IllegalArgumentException("Unsupported URI " + uri);
}
}
#Override
public Uri insert(Uri uri, ContentValues values) {
long rowID = sqlDB.insert(TABLE_NAME, null, values);
if (rowID > 0) {
Uri _uri = ContentUris.withAppendedId(CONTENT_URL, rowID);
getContext().getContentResolver().notifyChange(_uri, null);
return uri;
} else {
Toast.makeText(getContext(), "Row insert failed", Toast.LENGTH_SHORT).show();
return null;
}
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int rowsDeleted = 0;
switch (uriMatcher.match(uri)) {
case uriCode:
rowsDeleted = sqlDB.delete(TABLE_NAME, 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 rowsUpdated = 0;
switch (uriMatcher.match(uri)) {
case uriCode:
rowsUpdated = sqlDB.update(TABLE_NAME, values, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase sqlDB) {
sqlDB.execSQL(CREATE_DB_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase sqlDB, int oldVersion, int newVersion) {
sqlDB.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(sqlDB);
}
}
}
The addPlanToProviderFunction() method:
private void addPlanToProvider(long timeInMillis, String eventName) {
ContentValues values = new ContentValues();
values.put(PlansProvider.name, eventName);
values.put(PlansProvider.date, timeInMillis);
Uri uri = mContext.getContentResolver().insert(PlansProvider.CONTENT_URL, values);
}
The class in the second app where I want to get the data:
package com.example.piotr.zadaniowiec;
public class PlanList extends AppCompatActivity {
static final Uri CONTENT_URL = Uri.parse("content://com.example.piotr.planer.PlansProvider.cpplans");
ContentResolver resolver;
TextView planListTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_plans_list);
planListTextView = findViewById(R.id.plan_list_text_view);
resolver = getContentResolver();
getPlans();
}
private void getPlans() {
String[] projection = new String[]{"id", "name", "date"};
Cursor cursor = resolver.query(CONTENT_URL, projection, null, null, null);
String planList = "";
if (cursor.moveToNext()) { // I get an error here
do {
String id = cursor.getString(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
long date = cursor.getLong(cursor.getColumnIndex("date"));
planList = planList + id + name + date + "\n";
} while (cursor.moveToNext());
}
planListTextView.setText(planList);
}
}
I get :
"NullPointerException: Attempt to invoke interface method 'boolean android.database.Cursor.moveToNext()' on a null object reference."
Thanks anyone for the help.
Your CONTENT_URL is in the wrong format - you need a / after the authority, not a .
static final Uri CONTENT_URL =
Uri.parse("content://com.example.piotr.planer.PlansProvider/cpplans");
As it is now, you're looking for the root path for a ContentProvider that has an authority of com.example.piotr.planer.PlansProvider.cpplans, which doesn't exist, hence the null Cursor.

Failed to find provider info error

I am trying to have a contentprovider , but I am having trouble because I am getting an error of "Failed to find provider info for com.example.alex.hopefulyworks"
Here is the manifest and the contentprovider
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.alex.hopefulythisworks" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:name=".ColorContentProvider"
android:authorities="com.example.alex.hopefulythisworks.ColorContentProvider"
android:enabled="true"
android:exported="true" >
</provider>
</application>
</manifest>
package com.example.alex.hopefulythisworks;
....
public class ColorContentProvider extends ContentProvider {
private ColorHelper database;
private static final String AUTHORITY
= "com.example.alex.hopefulythisworks";
private static final String BASE_PATH
= "tasks";
public static final Uri CONTENT_URI
= Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
public static final String CONTENT_URI_PREFIX
= "content://" + AUTHORITY + "/" + BASE_PATH + "/";
private static final UriMatcher sURIMatcher =
new UriMatcher(UriMatcher.NO_MATCH);
private static final int COLOR = 1;
private static final int COLOR_ROW = 2;
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH, COLOR);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", COLOR_ROW);
}
#Override
public boolean onCreate() {
database = new ColorHelper(getContext());
Log.d("contentprovider" , "inside content provider oncreate ");
return false;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
long id = 0;
switch (uriType) {
case COLOR:
id = sqlDB.insert(ColorTable.TABLE_TASK,
null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: "
+ uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse( CONTENT_URI_PREFIX + id);
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// check if the caller has requested a column which does not exists
ColorTable.validateProjection( projection );
// Using SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables( ColorTable.TABLE_TASK );
switch ( sURIMatcher.match(uri) ) {
case COLOR:
break;
case COLOR_ROW:
// add the task ID to the original query
queryBuilder.appendWhere( ColorTable.COLUMN_ID + "=" + uri.getLastPathSegment() );
break;
default:
throw new IllegalArgumentException("Invalid URI: " + uri);
}
System.out.println("before null check");
if(database == null){
System.out.println("database is null");
database = new ColorHelper(getContext());
}
System.out.println("after null check");
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query( db, projection, selection,
selectionArgs, null, null, sortOrder);
// notify listeners
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch ( sURIMatcher.match(uri) ) {
case COLOR:
rowsDeleted = sqlDB.delete(ColorTable.TABLE_TASK, selection, selectionArgs);
break;
case COLOR_ROW:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete( ColorTable.TABLE_TASK,
ColorTable.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete( ColorTable.TABLE_TASK,
ColorTable.COLUMN_ID + "=" + id
+ " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Invalid URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection , String[] selectionArgs) {
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
switch ( sURIMatcher.match(uri) ) {
case COLOR:
rowsUpdated = sqlDB.update( ColorTable.TABLE_TASK,
values,
selection,
selectionArgs);
break;
case COLOR_ROW:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update( ColorTable.TABLE_TASK,
values,
ColorTable .COLUMN_ID + "=" + id,
null );
} else {
rowsUpdated = sqlDB.update( ColorTable.TABLE_TASK,
values,
ColorTable.COLUMN_ID + "=" + id
+ " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Invalid URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
}
authorities need to have only the package name, and name is the complete package and class name.
<provider android:name="com.example.alex.hopefulythisworks.ColorContentProvider"
android:authorities="com.example.alex.hopefulythisworks"
android:enabled="true"
android:exported="true" >
</provider>
Remember that this needs to match the same that you're using to build the Uri:
private static final String AUTHORITY = "com.example.alex.hopefulythisworks";
Android docs
android:authorities="com.example.alex.hopefulythisworks.ColorContentProvider"
should be the same as
private static final String AUTHORITY
= "com.example.alex.hopefulythisworks";
so another solution is replace AUTHORITY to
private static final String AUTHORITY
= "com.example.alex.hopefulythisworks.ColorContentProvider";
Hope it helps.
Just make sure you're using fully qualified name as authority in your searchable as well in provider declared in manifest file like below:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:hint="#string/action_search"
android:label="#string/app_name"
android:searchSuggestAuthority="your_pakcage_name.SearchSuggestionProvider"
android:searchSuggestSelection=" ?" />
<provider
android:authorities="your_pakcage_name.SearchSuggestionProvider"
android:name="your_pakcage_name.SearchSuggestionProvider"
android:exported="true"
android:enabled="true"
android:multiprocess="true"/>
If you've sensitive information in your providers make sure exported is not true
<provider
android:name="com.example.absolutelysaurabh.todoapp.ColorContentProvider"
android:authorities="com.example.absolutelysaurabh.todoapp"
android:enabled="true"
android:exported="false" >
</provider>
IMPORTANT : Make sure in the "Contract" class u've also used the same AUTHORITY as used here i.e. "com.example.absolutelysaurabh.todoapp"
(SOLVED)
I got this issue with my AddStickerPackActivity.java in function createIntentToAddStickerPack
where I commented intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_AUTHORITY, BuildConfig.CONTENT_PROVIDER_AUTHORITY); after watching some tutorials
Please check if you also find the same issue
Uncomment this line and make sure you are not importing any BuildConfig library, is it not required to import any BuildConfig
This might be old, the given answer works fine with APIs before API 30...
But for API 30 and API 31 checkout this:
Failed to find Content Provider in API 30

URIMatcher doesn't match

This was working! I'm not sure what changed. I do use git and I have looked over my commits and the code for hours now.
As the title indicates my uri matcher stopped matching.
Below I have pasted the relevant parts of my content provider.
public class Provider extends ContentProvider {
private static final String TAG = "Provider";
private static final String SCHEME = ContentResolver.SCHEME_CONTENT;
private static final String AUTHORITY = "com.snot.bodyweightworkout.database.provider";
private static final String BASE_URI = SCHEME + AUTHORITY;
public static final Uri URI_EXERCISES = Uri.parse(BASE_URI + "/exercise");
public static final Uri URI_PROGRAMS = Uri.parse(BASE_URI + "/program");
public static final Uri URI_PROGRAM_EXERCISES = Uri.parse(BASE_URI + "/program/#/exercise");
private static final int EXERCISE = 1;
private static final int EXERCISES = 2;
private static final int PROGRAM = 3;
private static final int PROGRAMS = 4;
private static final int PROGRAM_EXERCISES = 5;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static
{
sURIMatcher.addURI(AUTHORITY, "/exercise", EXERCISES);
sURIMatcher.addURI(AUTHORITY, "/exercise/#", EXERCISE);
sURIMatcher.addURI(AUTHORITY, "/program", PROGRAMS);
sURIMatcher.addURI(AUTHORITY, "/program/#", PROGRAM);
sURIMatcher.addURI(AUTHORITY, "/program/#/exercise", PROGRAM_EXERCISES);
}
...
And then the part where the actual matching should take place.
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.v(TAG, "URI: " + uri);
Cursor result = null;
int match = sURIMatcher.match(uri);
switch(match)
{
case PROGRAMS:
result = DatabaseHandler
.getInstance(getContext())
.getReadableDatabase()
.query(Program.TABLE_NAME, Program.FIELDS, null, null, null, null, null, null);
result.setNotificationUri(getContext().getContentResolver(), URI_PROGRAMS);
break;
case PROGRAM:
final long pid = Long.parseLong(uri.getLastPathSegment());
result = DatabaseHandler
.getInstance(getContext())
.getReadableDatabase()
.query(Program.TABLE_NAME, Program.FIELDS,
Program.COL_ID + " IS ?",
new String[] { String.valueOf(pid) }, null, null, null, null);
result.setNotificationUri(getContext().getContentResolver(), URI_PROGRAMS);
break;
...
default:
throw new UnsupportedOperationException("Unmatched(" + match + ") URI: " + uri.toString());
I'm trying to query using a cursor loader like this:
getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getActivity(), Provider.URI_PROGRAMS, Program.FIELDS, null, null, null);
}
Everytime default is hit. Not match is made the I end up with a FC and the following line in my log.
E/AndroidRuntime( 1979): Caused by: java.lang.UnsupportedOperationException: Unmatched(-1) URI: content://com.snot.bodyweightworkout.database.provider/program
I've been starring at this for hours and I really need some fresh eyes to take a peak at it. So if some kind soul could take a look at it I will appreciate it very much. Thanks in advance.
There's no need for the starting /, so define your addUri() method calls like this:
static {
sURIMatcher.addURI(AUTHORITY, "exercise", EXERCISES);
sURIMatcher.addURI(AUTHORITY, "exercise/#", EXERCISE);
sURIMatcher.addURI(AUTHORITY, "program", PROGRAMS);
sURIMatcher.addURI(AUTHORITY, "program/#", PROGRAM);
sURIMatcher.addURI(AUTHORITY, "program/#/exercise", PROGRAM_EXERCISES);
}

Categories

Resources