【Content Provider】uri.getPathSegments.get()解析

本文详细介绍了如何使用getPathSegments方法从特定的URI中解析出路径和ID,这对于理解和操作复杂的数据引用非常有帮助。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在URI content://com.example.app.provider/table1/#
使用uri.getPathSegments会将URI权限之后的部分即从table1开始的部分按“/”进行分割,所以这个列表中的第0个位置存放的就是路径,第一个位置存放的就是Id了。

package com.example.datarestore; import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; public class DatabaseProvider extends ContentProvider { public static final int BOOK_ANY = 0; public static final int BOOK_ITEM = 1; private MyDatabaseHelper myDatabaseHelper; private static UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.example.datarestore.provider","Book",BOOK_ANY); uriMatcher.addURI("com.example.datarestore.provider","Book/#",BOOK_ITEM); } public DatabaseProvider() { } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); int deleteRow = 0; if(uriMatcher.match(uri) == BOOK_ANY){ deleteRow = db.delete("Book",selection,selectionArgs); } else if (uriMatcher.match(uri) == BOOK_ITEM) { String Id = uri.getPathSegments().get(1); deleteRow = db.delete("Book","id = ?",new String[]{Id}); } return deleteRow; } @Override public String getType(Uri uri) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); String type = ""; if(uriMatcher.match(uri) == BOOK_ANY){ type = "vnd.android.cursor.dir/vnd.com.example.datarestore.provider.Book"; } else if (uriMatcher.match(uri) == BOOK_ITEM) { String Id = uri.getPathSegments().get(1); type = "vnd.android.cursor.item/vnd.com.example.datarestore.provider.Book"; } return type; } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); long newId = db.insert("Book",null,values); Uri returnuri = Uri.parse("content://com.example.datarestore.provider/Book/"+newId); return returnuri; } @Override public boolean onCreate() { myDatabaseHelper = new MyDatabaseHelper(getContext(),"Bookstore.db",null,1); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); Cursor cursor = null; if(uriMatcher.match(uri) == BOOK_ANY){ cursor = db.query("Book",projection,selection,selectionArgs,null,null,sortOrder); } else if (uriMatcher.match(uri) == BOOK_ITEM) { String Id = uri.getPathSegments().get(1); cursor = db.query("Book",projection,"id = ?",new String []{Id},null,null,sortOrder); } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); int updateRow = 0; if(uriMatcher.match(uri) == BOOK_ANY){ updateRow = db.update("Book",values,selection,selectionArgs); } else if (uriMatcher.match(uri) == BOOK_ITEM) { String Id = uri.getPathSegments().get(1); updateRow = db.update("Book",values,"id = ?",new String[]{Id}); } return updateRow; } }为什么初始化数据库没创建,其他程序显示找不到这个uri
07-26
<think>根据用户的问题描述,错误信息为`java.lang.IllegalArgumentException: Unknown URL content://com.example.datarestore.provider/Book`,这表示ContentProvider无法识别该URI。结合之前的回答,我们重点排查两个核心问题:URI匹配失败和数据库初始化问题。 ### 问题分析 1. **URI匹配失败**:`UriMatcher`没有正确匹配到`content://com.example.datarestore.provider/Book`,可能原因包括: - `UriMatcher`注册路径错误(如大小写、路径层级) - 清单文件(AndroidManifest.xml)中声明的authority与代码中不匹配 2. **数据库未正确初始化**:导致ContentProvider无法提供数据,可能原因: - `MyDatabaseHelper`实例未在`onCreate()`中正确初始化 - 数据库文件未创建或升级失败 ### 解决方案 #### 步骤1:检查ContentProvider声明 在`AndroidManifest.xml`中确保以下配置正确: ```xml <application ...> <provider android:name=".DatabaseProvider" android:authorities="com.example.datarestore.provider" android:exported="true" /> <!-- 如果允许其他应用访问,否则设为false --> </application> ``` **关键点**: - `android:authorities`必须与代码中`UriMatcher`注册的authority完全一致(包括大小写)。 #### 步骤2:修正UriMatcher注册 修改`DatabaseProvider`类中的静态初始化块,确保路径注册正确: ```java private static final String AUTHORITY = "com.example.datarestore.provider"; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 注册基础路径: content://com.example.datarestore.provider/Book uriMatcher.addURI(AUTHORITY, "Book", BOOK_ANY); // 注册带ID的路径: content://com.example.datarestore.provider/Book/# uriMatcher.addURI(AUTHORITY, "Book/#", BOOK_ITEM); } ``` #### 步骤3:验证数据库初始化 确保`onCreate()`方法中正确初始化`MyDatabaseHelper`: ```java @Override public boolean onCreate() { // 使用getContext()获取应用上下文 myDatabaseHelper = new MyDatabaseHelper(getContext(), "Bookstore.db", null, 1); return true; // 返回true表示初始化成功 } ``` #### 步骤4:调试数据库创建 在`MyDatabaseHelper`中重写`onCreate()`和`onUpgrade()`方法,确保数据库表被正确创建: ```java public class MyDatabaseHelper extends SQLiteOpenHelper { private static final String CREATE_BOOK = "CREATE TABLE Book (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "title TEXT, " + "author TEXT)"; public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); // 创建Book表 } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 升级逻辑(如有) } } ``` #### 步骤5:处理查询请求 在`query()`方法中,确保对两种URI模式(BOOK_ANY和BOOK_ITEM)都进行处理: ```java @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = myDatabaseHelper.getReadableDatabase(); // 使用读数据库 Cursor cursor; switch (uriMatcher.match(uri)) { case BOOK_ANY: cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder); break; case BOOK_ITEM: String id = uri.getPathSegments().get(1); cursor = db.query("Book", projection, "id=?", new String[]{id}, null, null, sortOrder); break; default: throw new IllegalArgumentException("Unknown URI: " + uri); } return cursor; } ``` ### 常见错误排查 | 错误类型 | 解决方案 | |---------|---------| | **URI大小写不一致** | 确保注册路径`"Book"`与调用方URI的`Book`大小写一致 | | **缺少路径注册** | 同时注册基础路径(`Book`)和带ID路径(`Book/#`) | | **数据库未创建** | 检查`MyDatabaseHelper`的`onCreate()`是否执行(通过Log输出验证) | | **ContentProvider未声明** | 确认`AndroidManifest.xml`中已声明`<provider>` | | **权限问题** | 如果跨应用访问,需在调用方声明`<queries>`(见引用[1]) | ### 跨应用访问配置(可选) 如果调用方是另一个应用(如`com.example.providertest`),需在其`AndroidManifest.xml`中添加: ```xml <queries> <provider android:authorities="com.example.datarestore.provider" /> </queries> ``` ### 最终验证步骤 1. 在`DatabaseProvider`的`onCreate()`中打印日志,确认数据库初始化成功。 2. 在`query()`方法开头打印URI和匹配码,验证URI匹配逻辑。 3. 使用`adb shell`检查数据库文件是否创建: ```bash adb shell run-as com.example.datarestore ls databases/ ``` 通过以上步骤,`Unknown URI`错误和数据库初始化问题将得到解决。 ### 相关问题 1. ContentProvider如何实现数据变更通知? 2. 如何为ContentProvider添加权限控制? 3. SQLite数据库版本升级的最佳实践是什么? 4. 如何通过Loader或ViewModel加载ContentProvider数据? 5. ContentProvider的性能优化有哪些方法?</think>### ContentProvider URI 无法识别与数据库初始化问题分析 根据错误信息 `java.lang.IllegalArgumentException: Unknown URL content://com.example.datarestore.provider/Book`,以下是核心问题分析和解决方案: --- ### 一、URI 无法识别的根本原因 1. **UriMatcher 注册缺失基础路径** 您的代码只注册了带ID的路径(`Book/#`),但未注册基础路径 `Book`: ```java // 当前注册 uriMatcher.addURI("com.example.datarestore.provider", "Book/#", BOOK_ITEM); // 带ID路径 // 缺少基础路径注册 uriMatcher.addURI("com.example.datarestore.provider", "Book", BOOK_ANY); // 缺失的基础路径 ``` 2. **AndroidManifest.xml 配置问题** Provider 声明可能缺少权限或路径配置: ```xml <provider android:name=".DatabaseProvider" android:authorities="com.example.datarestore.provider" android:exported="true" <!-- 允许外部访问 --> android:readPermission="com.example.datarestore.READ_PERMISSION" <!-- 可选权限 --> /> ``` 3. **跨应用访问限制**(Android 11+) 调用方应用需在清单中添加 `<queries>` 声明(引用[1]): ```xml <!-- 在调用方应用的 AndroidManifest.xml 中 --> <queries> <provider android:authorities="com.example.datarestore.provider" /> </queries> ``` --- ### 二、数据库未正确初始化的原因 1. **SQLiteOpenHelper 未实例化** `onCreate()` 方法中需要确保初始化: ```java @Override public boolean onCreate() { // 必须使用 getContext() 获取应用上下文 myDatabaseHelper = new MyDatabaseHelper(getContext(), "Bookstore.db", null, 1); return true; // 返回 true 表示初始化成功 } ``` 2. **数据库表创建失败** 检查 `MyDatabaseHelper` 是否创建了 Book 表: ```java public class MyDatabaseHelper extends SQLiteOpenHelper { private static final String CREATE_BOOK = "CREATE TABLE Book (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "title TEXT, " + "author TEXT)"; @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); // 执行建表语句 } } ``` --- ### 三、完整解决方案 #### 步骤1:修复 UriMatcher 注册 ```java static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 注册基础路径 uriMatcher.addURI("com.example.datarestore.provider", "Book", BOOK_ANY); // 注册带ID路径 uriMatcher.addURI("com.example.datarestore.provider", "Book/#", BOOK_ITEM); } ``` #### 步骤2:修正 ContentProvider 方法 在 `query`/`update`/`delete` 中处理两种 URI: ```java @Override public Cursor query(Uri uri, ...) { switch (uriMatcher.match(uri)) { case BOOK_ANY: // 处理 /Book cursor = db.query("Book", ...); break; case BOOK_ITEM: // 处理 /Book/# String id = uri.getLastPathSegment(); cursor = db.query("Book", "id=?", new String[]{id}, ...); break; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } return cursor; } ``` #### 步骤3:确保数据库初始化 ```java @Override public boolean onCreate() { // 使用正确的上下文初始化 myDatabaseHelper = new MyDatabaseHelper( getContext(), // 使用 ContentProvider 的上下文 "Bookstore.db", // 数据库名 null, // CursorFactory 1 // 版本号 ); return true; // 必须返回 true } ``` #### 步骤4:添加跨应用支持(Android 11+) ```xml <!-- 在调用方应用的 AndroidManifest.xml --> <manifest ...> <queries> <provider android:authorities="com.example.datarestore.provider" /> </queries> </manifest> ``` --- ### 四、验证步骤 1. **检查数据库创建** 在设备上查看数据库文件: `adb shell run-as com.example.datarestore ls databases/` 应能看到 `Bookstore.db` 文件 2. **测试 URI 访问** 使用 adb 命令测试: ```bash adb shell content query --uri content://com.example.datarestore.provider/Book ``` 3. **添加 Provider 日志** 在关键方法中添加日志: ```java @Override public Cursor query(Uri uri, ...) { Log.d("Provider", "Query URI: " + uri); int match = uriMatcher.match(uri); Log.d("Provider", "Match code: " + match); // ... } ``` --- ### 五、URI 规范要点(引用[2][3]) 1. **标准格式**:`content://<authority>/<path>` 2. **Authority 规则**:使用包名格式(如 `com.example.provider`) 3. **路径层级**: - 基础路径:`/Book`(集合) - 具体项:`/Book/5`(单条记录) 4. **MIME 类型规范**: ```java @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case BOOK_ANY: return "vnd.android.cursor.dir/vnd.com.example.provider.book"; case BOOK_ITEM: return "vnd.android.cursor.item/vnd.com.example.provider.book"; } } ``` --- ### 相关问题 1. 如何为 ContentProvider 添加数据变更通知机制? 2. Android 11+ 的包可见性限制如何影响 ContentProvider? 3. 如何通过 ContentResolver 批量操作 ContentProvider 数据? 4. ContentProvider 的权限控制有哪些最佳实践? 5. SQLiteOpenHelper 的数据库升级策略有哪些?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值