Android内容提供器——创建自己的内容提供器

创建自己的内容提供器很简单,只需要新建一个类继承ContentProvider类,并重写其中的6个抽象方法即可。(需要全部重写)

一 URI的写法

一个标准的内容URI写法有两种:

1.路径结尾,表示访问表中所有内容:

content://com.example.app.provider/table1

// * 可以代表任意长度的任意字符,所以也可以写成下面这样
content://com.example.app.provider/*

2.id结尾,表示访问表中特定id的内容:

content://com.example.app.provider/table1/1

// # 可以代表任意长度的数字,所以也可以写成下面这样
content://com.example.app.provider/table1/#

二 借助UriMatcher类

在UriMatcher类中提供了addURI()方法,传入三个参数,分别是authority,path,和一个自定义代码。

在UriMatcher类中提供了match()方法,传入一个Uri对象,返回值就是addUri中该uri对应的自定义代码。利用这个自定义代码,我们就可以判断出调用期望访问的数据。

代码如下:

 1 public class MyProvider extends ContentProvider {
 2
 3
 4     public static final int TABLE1_DIR = 0; //访问表1的所有数据
 5     public static final int TABLE1_ITEM = 1; //访问表1的单条数据
 6     public static final int TABLE2_DIR = 2;
 7     public static final int TABLE2_ITEM = 3;
 8
 9     private static UriMatcher uriMatcher;
10
11     /*静态代码块,通过adduri方法,将期望匹配的uri格式传入,并定义返回的自定义代码*/
12     static {
13         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
14         uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR);
15         uriMatcher.addURI("com.example.app.provider","table1/#",TABLE1_ITEM);
16         uriMatcher.addURI("com.example.app.provider","table2",TABLE2_DIR);
17         uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);
18     }
19
20
21     @Override
22     public boolean onCreate() {
23         return false;
24     }
25
26     @Nullable
27     @Override
28     public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
29         switch (uriMatcher.match(uri)){
30             case TABLE1_DIR:
31                 //查询table1表中的所有数据
32                 break;
33             case TABLE1_ITEM:
34                 //查询table1表中的单条数据
35                 break;
36             case TABLE2_DIR:
37                 //查询table2表中的所有数据
38                 break;
39             case TABLE2_ITEM:
40                 //查询table2表中的单条数据
41                 break;
42             default:
43                 break;
44         }
45         return null;
46     }
47     ···
48 )

除此之外,还有重写getType()方法,用于获得uri对象对应的mime类型,一个内容URI对应的MIME字符串又三部分组成:

//如果是路径结尾
vnd. + android.cursor.dir/ + vnd.<authority>.<paht>
//如:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1

//如果是id结尾
vnd. + android.cursor.item/ + vnd.<authority>.<paht>
//如
vnd.android.cursor.item/vnd.com.example.app.provider.table1

代码如下:

 1     @Override
 2     public String getType(@NonNull Uri uri) {
 3         switch (uriMatcher.match(uri)){
 4             case TABLE1_DIR:
 5                 return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
 6             case TABLE1_ITEM:
 7                 return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
 8             case TABLE2_DIR:
 9                 return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";
10             case TABLE2_ITEM:
11                 return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";
12             default:
13                 break;
14         }
15         return null;
16     }

三 实例使用内容提供器

构造一个数据库的内容提供器如下:

  1 public class MyContentProvider extends ContentProvider {
  2     public MyContentProvider() {
  3     }
  4
  5     public static final int BOOK_DIR = 0;
  6     public static final int BOOK_ITEM = 1;
  7     public static final int CATEGORY_DIR = 2;
  8     public static final int CATEGORY_ITEM = 3;
  9
 10     public static final String AUTHORITY = "com.example.databasetest,provider";
 11     private static UriMatcher uriMatcher;
 12     private MyDatabaseHelper dbHelper;
 13
 14     static {
 15         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 16         uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
 17         uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
 18         uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
 19         uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
 20     }
 21
 22     @Override
 23     public boolean onCreate() {
 24         // TODO: Implement this to initialize your content provider on startup.
 25         dbHelper = new MyDatabaseHelper(getContext(), "BookStore,db", null, 2);
 26         return true;
 27     }
 28
 29     @Override
 30     public Cursor query(Uri uri, String[] projection, String selection,
 31                         String[] selectionArgs, String sortOrder) {
 32         // TODO: Implement this to handle query requests from clients.
 33         Cursor cursor = null;
 34         SQLiteDatabase db = dbHelper.getReadableDatabase();
 35         switch (uriMatcher.match(uri)) {
 36             case BOOK_DIR:
 37                 cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
 38                 break;
 39             case BOOK_ITEM:
 40                 //getPathSegments将path部分以/为界分开,并将其放入字符串数据中,所以0对应path路径,1对应具体id
 41                 String bookId = uri.getPathSegments().get(1);
 42                 cursor = db.query("Book", projection, "id = ?", new String[]{bookId}, null, null, sortOrder);
 43                 break;
 44             case CATEGORY_DIR:
 45                 cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
 46                 break;
 47             case CATEGORY_ITEM:
 48                 String categoryId = uri.getPathSegments().get(1);
 49                 cursor = db.query("Category", projection, "id = ?", new String[]{categoryId}, null, null, sortOrder);
 50                 break;
 51             default:
 52                 break;
 53         }
 54         return cursor;
 55     }
 56
 57     @Override
 58     public Uri insert(Uri uri, ContentValues values) {
 59         // TODO: Implement this to handle requests to insert a new row.
 60         SQLiteDatabase db = dbHelper.getWritableDatabase();
 61         Uri uriReturn = null;
 62         switch (uriMatcher.match(uri)) {
 63             case BOOK_DIR:
 64             case BOOK_ITEM:
 65                 long newBookId = db.insert("Book", null, values);
 66                 uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
 67                 break;
 68             case CATEGORY_DIR:
 69             case CATEGORY_ITEM:
 70                 long newCategoryId = db.insert("Category", null, values);
 71                 uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
 72                 break;
 73             default:
 74                 break;
 75         }
 76         return uriReturn;
 77     }
 78
 79     @Override
 80     public int update(Uri uri, ContentValues values, String selection,
 81                       String[] selectionArgs) {
 82         // TODO: Implement this to handle requests to update one or more rows.
 83         SQLiteDatabase db = dbHelper.getWritableDatabase();
 84         int updatedRows = 0;
 85         switch (uriMatcher.match(uri)) {
 86             case BOOK_DIR:
 87                 updatedRows = db.update("Book", values, selection, selectionArgs);
 88                 break;
 89             case BOOK_ITEM:
 90                 String bookId = uri.getPathSegments().get(1);
 91                 updatedRows = db.update("Book", values, "id=?", new String[]{bookId});
 92                 break;
 93             case CATEGORY_DIR:
 94                 updatedRows = db.update("Category", values, selection, selectionArgs);
 95                 break;
 96             case CATEGORY_ITEM:
 97                 String CategoryId = uri.getPathSegments().get(1);
 98                 updatedRows = db.update("Category", values, "id=?", new String[]{CategoryId});
 99                 break;
100             default:
101                 break;
102         }
103         return updatedRows;
104     }
105
106     @Override
107     public int delete(Uri uri, String selection, String[] selectionArgs) {
108         // Implement this to handle requests to delete one or more rows.
109         SQLiteDatabase db = dbHelper.getWritableDatabase();
110         int deletedRows = 0;
111         switch (uriMatcher.match(uri)) {
112             case BOOK_DIR:
113                 deletedRows = db.delete("Book", selection, selectionArgs);
114                 break;
115             case BOOK_ITEM:
116                 String deletedBookId = uri.getPathSegments().get(1);
117                 deletedRows = db.delete("Book", "id=?", new String[]{deletedBookId});
118                 break;
119             case CATEGORY_DIR:
120                 deletedRows = db.delete("Category", selection, selectionArgs);
121                 break;
122             case CATEGORY_ITEM:
123                 String deletedCategoryId = uri.getPathSegments().get(1);
124                 deletedRows = db.delete("Category", "id=?", new String[]{deletedCategoryId});
125                 break;
126             default:
127                 break;
128         }
129         return deletedRows;
130     }
131
132     @Override
133     public String getType(Uri uri) {
134         // TODO: Implement this to handle requests for the MIME type of the data
135         // at the given URI.\
136         switch (uriMatcher.match(uri)) {
137             case BOOK_DIR:
138                 return "vnd.android.cursor.dir/vnd.com.example.app.provider.Book";
139             case BOOK_ITEM:
140                 return "vnd.android.cursor.item/vnd.com.example.app.provider.Book";
141             case CATEGORY_DIR:
142                 return "vnd.android.cursor.dir/vnd.com.example.app.provider.category";
143             case CATEGORY_ITEM:
144                 return "vnd.android.cursor.item/vnd.com.example.app.provider.category";
145             default:
146                 break;
147         }
148         return null;
149
150     }
151 }

代码整体可以分为几部分,首先是新建常量,用于访问book和category里中的数据,在静态代码块里对UriMatcher进行了addUri的配置。

在onCreate()方法中,创建了一个MyDatabaseHelper的实例,返回true表示初始化成功。

查询query()方法中,先获取到了SQLiteDatabase的实例,传入uri参数知道用户想访问的数据,然后在调用sqlitedatabase的query()方法进行查询,并将查询的cursor参数返回。如果是访问单条的数据,使用getPathSegments将path部分以“/”为界分开,并将其放入字符串数据中,所以0对应path路径,1对应具体id。得到id通过selection和selectionArgs来进行约束查询。最后返回cursor值。

新增insert()方法中,先获取到了SQLiteDatabase的实例,传入uri参数知道用户想往那张表加数据,然后在调用SQliteDatabase的insert()方法进行添加,返回的是一个能够表示这个新增数据的uri,这个内容uri是以新增数据的id结尾。所以还需要调用uri.parse()方法将其进行解析成uri对象。

更新update()方法中,先获取到了SQLiteDatabase的实例,传入uri参数知道用户想访问的数据,然后在调用sqlitedatabase的update()方法进行更新,受影响的行数作为返回值返回。

删除delete()方法中,先获取到了SQLiteDatabase的实例,传入uri参数知道用户想访问的数据,然后在调用sqlitedatabase的delete()方法进行删除,被删除的行数作为返回值返回。

最后是getType()方法,和之前的getType方法完全相同。

另外,内容提供器需要在AndroidManifest.xml中注册,一般as已经帮我们进行注册好了。

构建另外一个应用来使用我们的databasetest的内容提供器,新建一个应用,页面为四个按钮,布局如下:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="vertical">
 5
 6     <Button
 7         android:id="@+id/add_data"
 8         android:layout_width="match_parent"
 9         android:layout_height="wrap_content"
10         android:text="add to book"/>
11
12     <Button
13         android:id="@+id/query_data"
14         android:text="query from book"
15         android:layout_width="match_parent"
16         android:layout_height="wrap_content" />
17     <Button
18         android:id="@+id/update_data"
19         android:text="update book"
20         android:layout_width="match_parent"
21         android:layout_height="wrap_content" />
22     <Button
23         android:id="@+id/delete_data"
24         android:text="delete from book"
25         android:layout_width="match_parent"
26         android:layout_height="wrap_content" />
27 </LinearLayout>

然后在主函数中为四个按钮注册点击事件,并赋予相应的逻辑。

 1 public class MainActivity extends AppCompatActivity {
 2
 3     private String newId;
 4
 5     static final String path = "content://com.example.databasetest.provider/book";
 6
 7     @Override
 8     protected void onCreate(Bundle savedInstanceState) {
 9         super.onCreate(savedInstanceState);
10         setContentView(R.layout.activity_main);
11
12         Button addData = (Button) findViewById(R.id.add_data);
13         addData.setOnClickListener(new View.OnClickListener() {
14             @Override
15             public void onClick(View view) {
16                 Uri uri = Uri.parse(path);
17                 ContentValues values = new ContentValues();
18                 values.put("name", "a clash");
19                 values.put("author", "Mask");
20                 values.put("pages", 1002);
21                 values.put("price", 12.22);
22                 Uri newUri = getContentResolver().insert(uri, values);
23                 newId = newUri.getPathSegments().get(1);
24             }
25         });
26
27         Button queryData = (Button) findViewById(R.id.query_data);
28         queryData.setOnClickListener(new View.OnClickListener() {
29             @Override
30             public void onClick(View view) {
31                 Cursor cursor = null;
32                 Uri uri = Uri.parse(path);
33                 cursor = getContentResolver().query(uri, null, null, null, null);
34                 if (cursor != null) {
35                     while (cursor.moveToNext()) {
36                         String name = cursor.getString(cursor.getColumnIndex("name"));
37                         String author = cursor.getString(cursor.getColumnIndex("author"));
38                         int pages = cursor.getInt(cursor.getColumnIndex("pages"));
39                         double price = cursor.getDouble(cursor.getColumnIndex("price"));
40                         Log.d("MainActivity", "book name is " + name);
41                         Log.d("MainActivity", "book author is " + author);
42                         Log.d("MainActivity", "book pages is " + pages);
43                         Log.d("MainActivity", "book price is " + price);
44                     }
45                     cursor.close();
46                 }
47             }
48         });
49
50         Button updateData = (Button) findViewById(R.id.update_data);
51         updateData.setOnClickListener(new View.OnClickListener() {
52             @Override
53             public void onClick(View view) {
54                 Uri uri = Uri.parse(path + "/" + newId);
55                 ContentValues values = new ContentValues();
56                 values.put("name","The b");
57                 values.put("pages",12);
58                 values.put("price",12.22);
59                 getContentResolver().update(uri,values,null,null);
60             }
61         });
62
63         Button deleteData = (Button) findViewById(R.id.delete_data);
64         deleteData.setOnClickListener(new View.OnClickListener() {
65             @Override
66             public void onClick(View view) {
67                 Uri uri = Uri.parse(path + "/" + newId);
68                 getContentResolver().delete(uri,null,null);
69             }
70         });
71     }
72 }

其中我们将常用的uri设为一个常量path,每个内容Uri通过有path常量和“id”组成。而我们基本的操作就是先将内容uri进行解析,然后通过getContentResolver中的增删改查四种方法,传入相关的uri和values参数,进行操作。

其中增加中返回一个uri对象,这个对象中包含了新增数据的id,所以通过getPathSegments()方法将id取出,之后在更新和删除数据中,将这个id加在内容Uri尾部,使其只针对这一行数据进行操作。

原文地址:https://www.cnblogs.com/Mask-D/p/9532507.html

时间: 2024-10-13 05:35:53

Android内容提供器——创建自己的内容提供器的相关文章

转帖:Android 官方推荐 : DialogFragment 创建对话框

转: Android 官方推荐 : DialogFragment 创建对话框 复制内容,留作备份 1. 概述 DialogFragment在android 3.0时被引入.是一种特殊的Fragment,用于在Activity的内容之上展示一个模态的对话框.典型的用于:展示警告框,输入框,确认框等等.在DialogFragment产生之前,我们创建对话框:一般采用AlertDialog和Dialog.注:官方不推荐直接使用Dialog创建对话框. 2. 好处与用法 使用DialogFragment

Android提供的系统服务之--TelephonyManager(电话管理器)

Android提供的系统服务之--TelephonyManager(电话管理器) 转载请注明出处--coder-pig TelephonyManager的作用: 用于管理手机通话状态,获取电话信息(设备信息.sim卡信息以及网络信息), 侦听电话状态(呼叫状态服务状态.信号强度状态等)以及可以调用电话拨号器拨打电话! 如何获得TelephonyManager的服务对象: TelephonyManager tManager = (TelephonyManager)getSystemService(

Android应用开发基础之九:内容提供者

内容提供者 应用的数据库是不允许其他应用访问的 内容提供者的作用就是让别的应用访问到你的数据库 自定义内容提供者,继承ContentProvider类,重写增删改查方法,在方法中写增删改查数据库的代码,举例增方法 @Override public Uri insert(Uri uri, ContentValues values) { db.insert("person", null, values); return uri; } 在清单文件中定义内容提供者的标签,注意必须要有autho

其它内容选项----第二章:创建和管理内容

一个弹出式窗口将出现在其中您可以更新文本不留主页 (见图2-8).修改编辑器中的文本,然后单击保存按钮.新版本 您保存后的网页上会自动出现.这是执行快速文本的好方法 触摸起坐,你已经发现了或固定的错误. 图2-8.对网页内容编辑 如果进行一些修改,喜欢全屏幕编辑器界面中,单击铅笔图标(见 图2-7),然后选择编辑选项.这是因为点击任何内容项的标题来查看同一 内容详细页(即内容项目作为一个独立的页面的完整渲染),然后选择编辑选项卡 内容的标题下方,就像我们以前一样. 其它内容选项 在内容编辑表格的

评论设置----第二章:创建和管理内容

点击“保存并继续出版”按钮. Drupal将保存的内容项,现在该项目将 出现在主导航菜单上,用按字母顺序排列的菜单项.缺省情况下,菜单项 按字母顺序排序;你可以通过菜单管理工具更改排序顺序哪些 在第8章中讨论在这种情况下,我们是一个单件的内容链接到菜单项.在案件 要在其中多个内容项目链接到一个菜单项,你需要创建一个登陆页面(见 第7章)或视图(参见第10章).如果您使用的是标准Bartik主题(这是默认的主题 在Drupal 8),你应该看到靠近你的页面的顶部,您在“菜单中输入的值的新选项卡 链

URL路径设置----第二章:创建和管理内容

形式立即显示内容的下面.编辑内容,然后选择关闭选项,并点击 “保存并继续出版”按钮.你会发现在如何显示您的内容项的显著变化, 因为评论将不再出现. 图2-15.随着打开的默认设置,用户现在可以发布在网站上的评论 随着打开的默认设置,游客到您的网站现在可以编写和响应发表评论 你的内容项(假设你已经设置权限允许匿名用户发表评论, 我将在第6章盖).请尝试输入主题和注释,然后点击保存.你的评论 现在应该出现在注释部分. 由于内容作者(或该网站的管理员),你可以删除,编辑或回复评论 点击每个注释下的链接

预览和全展示----第二章:创建和管理内容

默认情况下,Drupal允许的内容项进行编辑,更新和删除该项目的作者.只有网站 这允许他们管理员或用户与角色进行编辑,更新和删除其他作者的内容可以 更改您的内容.如果您没有看到旁边的编辑内容项目的标题,那么你就不是 登录与适当的权限的帐户进行修改,该项目. 要更改内容项,单击编辑选项卡. Drupal将在编辑模式下显示的内容项, 在这里你可以更改或删除的项(见图2-6). 图2-6.内容将显示在编辑模式 还有另一种方式来编辑您的文章.尝试更新您在上一步中创建的文章 导航回主页.要导航回主页,点击

Android读取Assets文件夹中的内容

Android读取Assets文件夹中的内容 assets文件夹是android程序中存放相关外部文件的一个目录,Android官方提供了相应的方法去访问该文件夹中的内容,故此我们并不需要进行相关的路径判断等代码操作,直接调用相关方法打开文件并得到一个字节输入流(InputStream):然后通过相应的字符编码方式读取字节解码为字符输入流(InputStreamReader):再通过BufferReader对字符输入流读取文本并将字符存入缓冲区以便能提供字符.数组和线段的高效读取:最后我们就能逐

Android提供的系统服务之--AudioManager(音频管理器)

Android提供的系统服务之--AudioManager(音频管理器) ----转载请注明出处:coder-pig AudioManager相关简介与常用方法图: 简单的使用例子: 使用Mediaplayer播放音乐,通过AudioManager调节音量大小与静音: 这里,我们需要把要播放的音频文件放到res下的raw文件夹,这个文件夹默认是没有的,需要自己创建哦! 用来放原生资源的,就是打包编译的时候不会把他变成二进制文件!!! 先来看看效果图吧: 就是播放音乐,然后调高音量的时候可以看到滑