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对应的自定义代码。利用这个自定义代码,我们就可以判断出调用期望访问的数据。

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

代码如下:

 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 *");
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尾部,使其只针对这一行数据进行操作。

 

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

上一篇:移动端互动直播(入门篇)


下一篇:机器人到达导航点之后不再移动,无法旋转到目标方向。