IllegalArgumentException: Unknown URL content:// CONTENT

Phill Wiggins picture Phill Wiggins · Mar 20, 2015 · Viewed 20.5k times · Source

IllegalArgumentException: Unknown URL content://

^ Having a nightmare with the above. I've checked my variables and paths but can't see what the issue is? Greatly appreciate any pointers!

Here's my trace.

 java.lang.IllegalArgumentException: Unknown URL     
 content://com.purewowstudio.topmovies.data.FilmProvider/film_data
        at android.content.ContentResolver.insert(ContentResolver.java:1203)
        at com.purewowstudio.topmovies.data.DatabaseHelper.addFilm(DatabaseHelper.java:52)
        at com.purewowstudio.topmovies.fragments.FilmList$getFilms.onPostExecute(FilmList.java:72)
        at com.purewowstudio.topmovies.fragments.FilmList$getFilms.onPostExecute(FilmList.java:62)
        at android.os.AsyncTask.finish(AsyncTask.java:632)
        at android.os.AsyncTask.access$600(AsyncTask.java:177)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5262)
        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)

Content Provider

public class FilmProvider extends ContentProvider {

public static final String TABLE_NAME = "film_data";
public static final String AUTHORITY =  "com.purewowstudio.topmovies.data.FilmProvider";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME);

public static final int FILMS = 1;
public static final int FILMS_ID = 2;

public static final UriMatcher sURIMatcher =
        new UriMatcher(UriMatcher.NO_MATCH);

static {
    sURIMatcher.addURI(AUTHORITY, TABLE_NAME, FILMS);
    sURIMatcher.addURI(AUTHORITY, TABLE_NAME + "/#",
            FILMS_ID);
}

private DatabaseHelper mDB;

public boolean onCreate() {
    mDB = new DatabaseHelper(getContext(), null, null, 1);
    return false;
}

@Override
public String getType(Uri uri) {
    return null;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[]        selectionArgs, String sortOrder) {

    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    queryBuilder.setTables(MovieDataContract.TABLE_NAME);
    int uriType = sURIMatcher.match(uri);

    switch (uriType) {
        case FILMS_ID:
            queryBuilder.appendWhere(MovieDataContract.FilmEntry._ID + "="
                    + uri.getLastPathSegment());
            break;
        case FILMS:
            break;
        default:
            throw new IllegalArgumentException("Unknown URI");
    }

    Cursor cursor = queryBuilder.query(mDB.getReadableDatabase(),
            projection, selection, selectionArgs, null, null,
            sortOrder);
    cursor.setNotificationUri(getContext().getContentResolver(),
            uri);
    return cursor;

}

@Override
public Uri insert(Uri uri, ContentValues values) {

    int uriType = sURIMatcher.match(uri);

    SQLiteDatabase sqlDB = mDB.getWritableDatabase();

    long id = 0;
    switch (uriType) {
        case FILMS:
            id = sqlDB.insert(MovieDataContract.TABLE_NAME,
                    null, values);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI: "
                    + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return Uri.parse(MovieDataContract.TABLE_NAME + "/" + id);
}

DatabaseHelper Class

 public class DatabaseHelper extends SQLiteOpenHelper {

private ContentResolver myCR;

public DatabaseHelper(Context context, String name,
                      SQLiteDatabase.CursorFactory factory, int version) {
    super(context, MovieDataContract.DATABASE_NAME, factory, MovieDataContract.DATABASE_VERSION);

    myCR = context.getContentResolver();
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(MovieDataContract.FilmEntry.SQL_CREATE_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL(MovieDataContract.FilmEntry.DELETE_TABLE);
    onCreate(db);
}

public void addFilm(Film film){

    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put(MovieDataContract.FilmEntry.COLUMN_FILM_TITLE, film.getTitle());
    values.put(MovieDataContract.FilmEntry.COLUMN_FILM_RATING,  film.getRating());
    values.put(MovieDataContract.FilmEntry.COLUMN_FILM_RUNTIME,  film.getRuntime());
    values.put(MovieDataContract.FilmEntry.COLUMN_FILM_CRITICS,  film.getCritics());
    values.put(MovieDataContract.FilmEntry.COLUMN_FILM_AUDIENCE,  film.getAudience());
    values.put(MovieDataContract.FilmEntry.COLUMN_FILM_SYNOPSIS,  film.getSynopsis());
    values.put(MovieDataContract.FilmEntry.COLUMN_FILM_PROFILE,  film.getProfile());

    myCR.insert(FilmProvider.CONTENT_URI, values);

    db.insert(MovieDataContract.TABLE_NAME,
            null,
            values);
    db.close();
}

Manifest

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.INTERNET" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/TopMoviesTheme" >
    <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>
    <activity
        android:name=".DetailFragment"
        android:label="@string/title_activity_detail_fragment"
        android:parentActivityName=".MainActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.purewowstudio.topmovies.MainActivity" />
        <provider
            android:name=".data.filmProvider"
            android:authorities="com.purewowstudio.topmovies.data.filmProvider"
            android:exported="true">
        </provider>
    </activity>
</application>

</manifest>

Answer

CommonsWare picture CommonsWare · Mar 20, 2015

First, move <provider> to be a child of <application>, not <activity>.

Second, change android:exported="true" to android:exported="false", until such time as you secure your ContentProvider. As it stands, once you fix the <provider> element location as noted above, any app can read and write anything in your provider, which is unlikely to be what the user wants.