【问题标题】:Unknown Uri which causes more problems (Android)导致更多问题的未知 Uri (Android)
【发布时间】:2026-02-21 19:50:01
【问题描述】:

我已经尝试解决这个问题很长时间了。如果您需要更多信息,我会发布我认为足够的信息,然后请询问我。

public class PInfoProvider extends ContentProvider {
    private PInfoDatabase mOpenHelper;

    private static String TAG = PInfoProvider.class.getSimpleName();
    private static final UriMatcher sUriMatcher = buildUriMatcher();

    private static final int PINFOS = 100;
    private static final int PINFOS_ID = 101;

    private static UriMatcher buildUriMatcher(){
        final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
        final String authority = PInfoContract.CONTENT_AUTHORITY;
        matcher.addURI(authority, "PInfos", PINFOS);
        matcher.addURI(authority, "Pinfos/*", PINFOS_ID);
        return matcher;
    }
    @Override
    public boolean onCreate() {
        mOpenHelper = new PInfoDatabase(getContext());
        return true;
    }

    private void deleteDatabase(){
        mOpenHelper.close();
        PInfoDatabase.deleteDatabase(getContext());
        mOpenHelper = new PInfoDatabase(getContext());
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        final int match = sUriMatcher.match(uri);

        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(PInfoDatabase.Tables.PInfo);

        switch(match){
            case PINFOS:
                //do nothing
                break;
            case PINFOS_ID:
                String id = PInfoContract.PInfos.getPInfoId(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);
        //projection in content provider means the list of columns you want to return.
        return cursor;

    }

    @Override
    public String getType(Uri uri) {
        final int match = sUriMatcher.match(uri);
        switch(match){
            case PINFOS:
                return PInfoContract.PInfos.CONTENT_TYPE;
            case PINFOS_ID:
                return PInfoContract.PInfos.CONTENT_ITEM_TYPE;
            default:
                throw new IllegalArgumentException("Unknown Uri: " + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        //ContentValues: is a list of content values of our database such as the email and username. Contains the column names and the values we want to associate to it when we're writing to the database/
        Log.v(TAG, "insert(uri=" + uri + ", values =" + values.toString());

        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final int match = sUriMatcher.match(uri);

        switch(match){
            //only using the PInfo and not the ID becuase it's to insert only.
            case PINFOS:
                long recordID = db.insertOrThrow(PInfoDatabase.Tables.PInfo, null, values);
                return PInfoContract.PInfos.buildPInfoUri(String.valueOf(recordID));
            default:
                throw new IllegalArgumentException("Unknown Uri: " + uri);
        }
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        Log.v(TAG, "delete(uri=" + uri);

        if(uri.equals(PInfoContract.URI_TABLE)){
            deleteDatabase();
            return 0;
            //This will be executed if the user didn't input a valid record id.
            //Base content uri doesn't contain an ID nor a path.
        }
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final int match = sUriMatcher.match(uri);

        String selectionCriteria = selection;

        switch(match){

            /*
            case PInfo:
                If this was called and didn't "break" it would change all the records in the table.
                We will still leave it out because we added the database deletion code above.
                 break;
             */

            case PINFOS_ID:
                String id = PInfoContract.PInfos.getPInfoId(uri);
                selectionCriteria = BaseColumns._ID + "=" + id
                        + (!TextUtils.isEmpty(selection) ? "AND (" + selection + ")" : "");
                return db.delete(PInfoDatabase.Tables.PInfo, selectionCriteria, selectionArgs);

            default:
                throw new IllegalArgumentException("Unknown Uri: " + uri);
        }

    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        Log.v(TAG, "update(uri=" + uri + ", values =" + values.toString());

        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final int match = sUriMatcher.match(uri);

        String selectionCriteria = selection;
        //We set selectionCriteria to equal selection in the case PInfo case was chosen. After all,
        //we still need to record the selection.

        switch(match){
            case PINFOS:
                //do nothing
                //If this was called and didn't "break" it would change all the records in the table.
                break;
            case PINFOS_ID:
                String id = PInfoContract.PInfos.getPInfoId(uri);
                selectionCriteria = BaseColumns._ID + "=" + id
                    + (!TextUtils.isEmpty(selection) ? "AND (" + selection + ")" : "");
                break;

            default:
                throw new IllegalArgumentException("Unknown Uri: " + uri);
        }
        return db.update(PInfoDatabase.Tables.PInfo, values, selectionCriteria, selectionArgs);
    }
}

以及logcat中提到的其他类:

public class AddActivity extends FragmentActivity{

    private final String LOG_TAG = AddActivity.class.getSimpleName();
    private TextView mWebsiteTextView, mEmailTextView, mUsernameTextView, mPasswordTextView;
    private Button mButton;
    private ContentResolver mContentResolver;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.add_edit);
        getActionBar().setDisplayHomeAsUpEnabled(true); //returns up one level rather than back to the top level

        mWebsiteTextView = (TextView) findViewById(R.id.pinfoWebsite);
        mEmailTextView = (TextView) findViewById(R.id.pinfoEmail);
        mUsernameTextView= (TextView) findViewById(R.id.pinfoUsername);
        mPasswordTextView = (TextView) findViewById(R.id.pinfoPassword);

        mContentResolver = AddActivity.this.getContentResolver();

        mButton = (Button) findViewById(R.id.saveButton);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isValid()){
                    ContentValues values = new ContentValues(); //Content Values Class is used to store a set of values that the ContentResolver can process.
                    values.put(PInfoContract.PInfoColumns.PINFO_WEBSITE, mWebsiteTextView.getText().toString()); //.put add values ot the set & .toString() to convert it to the right format
                    values.put(PInfoContract.PInfoColumns.PINFO_EMAIL, mEmailTextView.getText().toString());
                    values.put(PInfoContract.PInfoColumns.PINFO_USERNAME, mUsernameTextView.getText().toString());
                    values.put(PInfoContract.PInfoColumns.PINFO_PASSWORD, mPasswordTextView.getText().toString());

                    Uri returned = mContentResolver.insert(PInfoContract.URI_TABLE, values);
                    Log.d(LOG_TAG, "record id returned is; " + returned);
                    Intent intent = new Intent(AddActivity.this, MainActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    startActivity(intent);
                    finish(); //always use this when the activity's process is finished
                }else {
                    Toast.makeText(getApplicationContext(), "Please make sure you have inputted valid data.", Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    private boolean isValid(){ //You can have this as complex as you want. Like checking other databases or number of charas.
        if(mWebsiteTextView.getText().toString().length() == 0 ||
                mEmailTextView.getText().toString().length() == 0 ||
                mUsernameTextView.getText().toString().length() == 0 ||
                mPasswordTextView.getText().toString().length() == 0 ){
            return false;
        }
        return true;
    }

    private boolean someDataEntered(){
        if(mWebsiteTextView.getText().toString().length() > 0 ||
                mEmailTextView.getText().toString().length() > 0 ||
                mUsernameTextView.getText().toString().length() > 0 ||
                mPasswordTextView.getText().toString().length() > 0 ){
            return true;
        }
        return false;
    }

    @Override
    public void onBackPressed() {
        if(someDataEntered()){
            PInfoDialog dialog = new PInfoDialog();
            Bundle args = new Bundle();
            args.putString(PInfoDialog.DIALOG_TYPE, PInfoDialog.CONFIRM_EXIT); //This method places a text string in the virtual screen at the specified location.
            dialog.setArguments(args);
            dialog.show(getSupportFragmentManager(), "confirm-exit");
        } else{
            super.onBackPressed(); //if someDataEntered() is false just do what usually happnes.
        }
    }
}

日志猫:

06-23 16:03:14.117 21940-21940/com.example.saleh.findmypassword E/ActivityThread:未能找到 com.example.saleh.findmypassword.PInfoProvider 的提供者信息 06-23 16:03:14.121 21940-21940/com.example.saleh.findmypassword W/dalvikvm: threadid=1: 线程退出未捕获异常 (group=0xa4c95b20) 06-23 16:03:14.121 21940-21940/com.example.saleh.findmypassword E/AndroidRuntime: 致命例外:主要 进程:com.example.saleh.findmypassword,PID:21940 java.lang.IllegalArgumentException:未知的 URL 内容://com.example.saleh.findmypassword.PInfoProvider/pinfos 在 android.content.ContentResolver.insert(ContentResolver.java:1186) 在 com.example.saleh.findmypassword.AddActivity$1.onClick(AddActivity.java:51) 在 android.view.View.performClick(View.java:4438) 在 android.view.View$PerformClick.run(View.java:18422) 在 android.os.Handler.handleCallback(Handler.java:733) 在 android.os.Handler.dispatchMessage(Handler.java:95) 在 android.os.Looper.loop(Looper.java:136) 在 android.app.ActivityThread.main(ActivityThread.java:5001) 在 java.lang.reflect.Method.invokeNative(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:515) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) 在 dalvik.system.NativeStart.main(Native Method)

清单:

<uses-permission android:name="com.example.saleh.findmypassword.provider.READWRITE" />
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.WithActionBar">
    <activity
        android:name=".MainActivity"
        android:label="Personal Info">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity
        android:name=".AddActivity"
        android:label="@string/add_pinfo_title"
        android:parentActivityName="com.example.saleh.findmypassword.MainActivity" />


    <activity
        android:name="com.example.saleh.findmypassword.EditActivity"
        android:label="@string/edit_pinfo_title"
        android:parentActivityName="com.example.saleh.findmypassword.MainActivity" />

    <activity
        android:name="com.example.saleh.findmypassword.SearchActivity"
        android:label="@string/search_pinfo_title"
        android:parentActivityName="com.example.saleh.findmypassword.MainActivity" />
    `````
    <provider
        android:name="com.example.saleh.findmypassword.PInfoProvider"
        android:authorities="com.example.saleh.findmypassword.provider"
        android:exported="true"
        android:readPermission="com.example.saleh.findmypassword.provider.READWRITE"
        android:writePermission="com.example.saleh.findmypassword.provider.READWRITE" />
</application>

这里是构建 uri 的位置:

公共类 PInfoContract {

public static final String CONTENT_AUTHORITY = "com.example.saleh.findmypassword.provider";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);

public static final String PATH_PINFOS = "pinfos";
public static final Uri URI_TABLE = Uri.parse(BASE_CONTENT_URI.toString() + "/" + PATH_PINFOS);

public static final String[] TOP_LEVEL_PATHS = {
        PATH_PINFOS
};

public static class PInfos implements PInfoColumns, BaseColumns {
    public static final Uri CONTENT_URI =
            BASE_CONTENT_URI.buildUpon().appendEncodedPath(PATH_PINFOS).build();
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd." + CONTENT_AUTHORITY + ".pinfos";
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd." + CONTENT_AUTHORITY + ".pinfos";

    public static Uri buildPInfoUri(String PInfoId) {
        return CONTENT_URI.buildUpon().appendEncodedPath(PInfoId).build();
    }

    public static String getPInfoId(Uri uri) {
        return uri.getPathSegments().get(1);
    }

}

}

【问题讨论】:

  • UriMatcher 可能区分大小写,而您的Uri 中的大小写错误。
  • 我认为问题出在提供程序包中,请发布您的 AndroidManifest.xml
  • 我认为 uri 问题请更改内容 uri 名称 请检查 Uri 名称与您的包名称(清单文件)com.example.saleh.findmypassword.provider 另一个原因是为提供者添加权限(如果缺少)
  • 添加了更多信息。
  • 更改:公共静态最终 Uri BASE_CONTENT_URI = Uri.parse("content://com.example.saleh.findmypassword.PInfoProvider");

标签: java android eclipse android-studio fatal-error


【解决方案1】:

既然你有这个例外:

    java.lang.IllegalArgumentException: Unknown Uri: 
content://com.example.saleh.findmypassword.provider/pinfos at 
com.example.saleh.findmypassword.PInfoProvider.insert(PInfoProvider.java:97>)

检查您的提供商的包,它不存在(未知 Uri):

com.example.saleh.findmypassword.provider

必须是:

com.example.saleh.findmypassword.PInfoProvider

更新:

将变量BASE_CONTENT_URI的值改为:

public static final Uri BASE_CONTENT_URI = Uri.parse("content://com.example.saleh.findmypassword.PInfoProvider"); 

【讨论】:

  • 我添加了清单文件。请检查一下,我认为我不应该更改名称。 PInfoProvider 是名称,而 authority 是提供者。如果没有,请建议我做任何事情。
  • 是的,你是对的!名称是 com.example.saleh.findmypassword.PInfoProvider 但在您的代码的某些部分中,您使用 com.example.saleh.findmypassword.provider 作为提供者的名称。
  • 有没有办法知道具体在哪里?
  • 将在几秒钟内发布正在构建 Uri 的类
最近更新 更多