ContentProvider基本使用
为了在应用程序之间交换数据,android提供了ContentProvider,ContentProvider是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他程序使用时,该应用程序就可以通过提供ContentPRovider来实现,其他应用程序就可以通过ContentResolver来操作ContentProvider暴露的数据。
实现ContentProvider的步骤:
1)编写一个类,继承ContentProvider,并且重写里面的CRUD方法。
2)在androidmanifest.xml文件中注册provider。
在androidmanifest.xml中注册provider需要以下3个属性:
android:name provider的实现类。
android:authorities provider的uri。
android:exported provider是否暴露给其他程序。
ContentResovler操作ContentProvider:
1)获取ContentResolver,getContentResovler()方法来自于ContextWrapper,所以activity和service中都可以使用。
2)调用CURD方法,通过参数url,调用指定的ContentProvider的方法。
下面是一个demo,向contentProvider中插入一条数据,并且返回到listview中。
main.xml:
1
2
3
4
5
6
7
8
9
10
11
12
|
<
RelativeLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
tools:context
=
".Main"
>
<
ListView
android:id
=
"@+id/listview"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
/>
RelativeLayout
>
|
MySQLiteOpenHelper类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package
com.app.dao;
import
android.content.Context;
import
android.database.sqlite.SQLiteDatabase;
import
android.database.sqlite.SQLiteDatabase.CursorFactory;
import
android.database.sqlite.SQLiteOpenHelper;
public
class
MySQLiteOpenHelper
extends
SQLiteOpenHelper {
public
MySQLiteOpenHelper(Context context, String name,
CursorFactory factory,
int
version) {
super
(context, name, factory, version);
}
@Override
public
void
onCreate(SQLiteDatabase db) {
String create_sql =
"create table tb_test(_id integer primary key autoincrement,name,gender,age)"
;
db.execSQL(create_sql);
}
@Override
public
void
onUpgrade(SQLiteDatabase db,
int
oldVersion,
int
newVersion) {
}
}
|
MyContentProvider类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
package
com.app.dao;
import
android.content.ContentProvider;
import
android.content.ContentValues;
import
android.database.Cursor;
import
android.net.Uri;
public
class
MyContentProvider
extends
ContentProvider{
MySQLiteOpenHelper helper=
null
;
@Override
public
int
delete(Uri arg0, String arg1, String[] arg2) {
return
0
;
}
@Override
public
String getType(Uri arg0) {
// TODO Auto-generated method stub
return
null
;
}
@Override
public
Uri insert(Uri arg0, ContentValues values) {
String insert_sql=
"insert into tb_test values(null,'wx','boy',17)"
;
helper.getReadableDatabase().execSQL(insert_sql);
return
null
;
}
@Override
public
boolean
onCreate() {
helper=
new
MySQLiteOpenHelper(
this
.getContext(),
"test.db3"
,
null
,
1
);
return
true
;
}
@Override
public
Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4) {
String query_sql=
"select * from tb_test"
;
Cursor cursor=helper.getReadableDatabase().rawQuery(query_sql,
null
);
return
cursor;
}
@Override
public
int
update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
// TODO Auto-generated method stub
return
0
;
}
}
|
listview的显示界面show.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:orientation
=
"horizontal"
>
<
TextView
android:id
=
"@+id/name"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
/>
<
TextView
android:id
=
"@+id/gender"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginLeft
=
"60dp"
/>
<
TextView
android:id
=
"@+id/age"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginLeft
=
"60dp"
/>
LinearLayout
>
|
Main.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
package
com.app.main;
import
android.annotation.SuppressLint;
import
android.app.Activity;
import
android.content.ContentResolver;
import
android.database.Cursor;
import
android.net.Uri;
import
android.os.Bundle;
import
android.support.v4.widget.CursorAdapter;
import
android.widget.ListView;
import
android.widget.SimpleCursorAdapter;
public
class
Main
extends
Activity {
ContentResolver resolver =
null
;
ListView lv =
null
;
@SuppressLint
(
"NewApi"
)
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
lv = (ListView)
this
.findViewById(R.id.listview);
resolver =
this
.getContentResolver();
String str =
"content://com.app.test.db/"
;
Uri uri = Uri.parse(str);
resolver.insert(uri,
null
);
Cursor cursor = resolver.query(uri,
null
,
null
,
null
,
null
);
SimpleCursorAdapter adapter =
new
SimpleCursorAdapter(
this
,
R.layout.show, cursor,
new
String[] {
"name"
,
"gender"
,
"age"
},
new
int
[] {
R.id.name, R.id.gender, R.id.age },
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(adapter);
}
}
|
实现效果:(执行了3次插入后的效果)
ContentProvider的单元测试
ContentProvider是android的四大组件之一,在编写代码的时候最好是加上单元测试,这样可以确定对数据的CRUD的正确。本篇文章主要介绍ContentProvider中两个主要辅助类的使用还有单元测试的在ContentProvider中的使用。
需要用到的两个辅助类:UriMatcher类和ContentUris类。
UriMatcher类:能够对输入的uri参数就行匹配,以确定对什么表执行什么样的操作。
ContentUris类:有些方法需要返回uri,运用此类可以方便的生成uri类。
对于单元测试,个人觉得非常有必要在今后写代码的时候使用,这样可以非常准确的确定代码的正确性。
使用单元测试的步骤:
1)加入instrumentation,这个部分的代码是固定,也可以完全在ADT提供的向导中导入。
1
2
3
4
|
<
instrumentation
android:name
=
"android.test.InstrumentationTestRunner"
android:targetPackage
=
"com.example.android_contentprovider"
>
instrumentation
>
|
2)添加
1
|
<
uses-library
android:name
=
"android.test.runner"
/>
|
好了,必备的知识已经讲完了,现在上代码:
1)生成一个SQLiteDatabase类,这个是必需的类MySQLiteOpenHelper类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package
com.app.db;
import
android.content.Context;
import
android.database.sqlite.SQLiteDatabase;
import
android.database.sqlite.SQLiteDatabase.CursorFactory;
import
android.database.sqlite.SQLiteOpenHelper;
public
class
MySQLiteOpenHelper
extends
SQLiteOpenHelper {
private
static
String DB_NAME =
"test.db3"
;
private
static
int
VERSION =
1
;
public
MySQLiteOpenHelper(Context context) {
super
(context, DB_NAME,
null
, VERSION);
}
@Override
public
void
onCreate(SQLiteDatabase db) {
//建表语句
String create_student =
"create table student(_id integer primary key autoincrement,name varchar(10),age integer,gender vachar(10))"
;
db.execSQL(create_student);
//千万不能执行这句 // db.close();
}
@Override
public
void
onUpgrade(SQLiteDatabase arg0,
int
arg1,
int
arg2) {
}
}
|
然后添加我们需要的MyContentProvider类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
package
com.app.contentprovider;
import
com.app.db.MySQLiteOpenHelper;
import
android.content.ContentProvider;
import
android.content.ContentUris;
import
android.content.ContentValues;
import
android.content.UriMatcher;
import
android.database.Cursor;
import
android.database.sqlite.SQLiteDatabase;
import
android.net.Uri;
import
android.util.Log;
public
class
MyContentProvider
extends
ContentProvider {
MySQLiteOpenHelper helper =
null
;
private
static
UriMatcher matcher =
new
UriMatcher(UriMatcher.NO_MATCH);
// 匹配单条记录
private
static
final
int
student =
1
;
// 匹配多条记录
private
static
final
int
students =
2
;
static
{
matcher.addURI(
"com.app.wx"
,
"student/#"
, student);
matcher.addURI(
"com.app.wx"
,
"student"
, students);
}
@Override
public
int
delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int
action = matcher.match(uri);
switch
(action) {
// 匹配单条记录
case
student:
long
id = ContentUris.parseId(uri);
//获取单条记录的id号
String delete_id =
"_id="
+ id;
if
(selection !=
null
) {
delete_id += delete_id +
" and "
+ selection;
}
db.delete(
"student"
, delete_id, selectionArgs);
break
;
// 匹配多条记录
case
students:
db.delete(
"student"
, selection, selectionArgs);
break
;
}
return
0
;
}
//必需实现这个方法,这个方法与intent有关系,以后再讲
@Override
public
String getType(Uri uri) {
int
code = matcher.match(uri);
switch
(code) {
case
student:
return
"vnd.android.cursor.item/student_item"
;
case
students:
return
"vnd.android.cursor.dir/students"
;
default
:
return
null
;
}
}
@Override
public
Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = helper.getWritableDatabase();
int
action = matcher.match(uri);
switch
(action) {
case
students:
long
id1 = db.insert(
"student"
,
"_id"
, values);
Log.i(
"--------"
, ContentUris.withAppendedId(uri, id1).toString());
return
ContentUris.withAppendedId(uri, id1);
}
return
null
;
}
@Override
public
boolean
onCreate() {
helper =
new
MySQLiteOpenHelper(
this
.getContext());
return
true
;
}
@Override
public
Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String orderBy) {
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor =
null
;
int
action = matcher.match(uri);
switch
(action) {
case
students:
cursor = db.query(
"student"
, projection, selection, selectionArgs,
null
,
null
, orderBy);
break
;
}
System.out.println(
"-----------count:"
+ cursor.getCount());
return
cursor;
}
@Override
public
int
update(Uri uri, ContentValues values, String selection,
String[] arg3) {
int
count = -
1
;
SQLiteDatabase db = helper.getWritableDatabase();
int
action = matcher.match(uri);
switch
(action) {
case
student:
// 以id来处理更新
long
id = ContentUris.parseId(uri);
String id_selection =
"_id="
+ id;
if
(selection !=
null
&& !selection.equals(
""
)) {
id_selection = id_selection +
" and "
+ values;
}
count = db.update(
"student"
, values, id_selection, arg3);
System.out.println(
"----------count:"
+ count);
break
;
}
return
count;
}
}
|
这个类很长,但是执行的方法都是比较常见的CURD的方法,重要的是UriMatcher和ContentUris类的使用。
接着执行单元测试类:Test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
package
com.app.contentprovider;
import
android.content.ContentResolver;
import
android.content.ContentValues;
import
android.database.Cursor;
import
android.net.Uri;
import
android.test.AndroidTestCase;
import
android.util.Log;
public
class
Test
extends
AndroidTestCase {
public
void
insert() {
ContentResolver resolver =
this
.getContext().getContentResolver();
String str =
"content://com.app.wx/student"
;
ContentValues values =
new
ContentValues();
values.put(
"name"
,
"wzq"
);
values.put(
"age"
,
18
);
values.put(
"gender"
,
"boy"
);
resolver.insert(Uri.parse(str), values);
}
public
void
update() {
ContentResolver resolver =
this
.getContext().getContentResolver();
String str =
"content://com.app.wx/student/2"
;
ContentValues values =
new
ContentValues();
values.put(
"name"
,
"哈哈"
);
resolver.update(Uri.parse(str), values,
null
,
null
);
}
public
void
query() {
ContentResolver resolver =
this
.getContext().getContentResolver();
String str =
"content://com.app.wx/student"
;
Uri uri = Uri.parse(str);
Cursor cursor = resolver.query(uri,
new
String[] {
"_id"
,
"name,age,gender"
},
null
,
null
,
"_id desc"
);
Log.d(
"------count"
,cursor.getCount()+
""
);
}
public
void
delete() {
ContentResolver resolver =
this
.getContext().getContentResolver();
String str =
"content://com.app.wx/student/2"
;
Uri uri = Uri.parse(str);
long
id=resolver.delete(uri,
null
,
null
);
}
}
|
执行insert方法之后(执行了三次):
执行了update方法之后:
执行了query方法之后:
执行了delete方法之后: