ContentProvider组件详细的使用方法

前言:这几天无聊,总结了以前学的知识点。



这篇文章主要介绍了Android中ContentProvider组件的使用方法,包括ContentProvider使用单元测试的步骤,需要的朋友可以参考下

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次插入后的效果)

2016421160202125.png (720×1280)

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)添加<uses-library>,这个部分的代码也是固定的写法。

?
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方法之后(执行了三次):

2016421160332881.png (463×93)

执行了update方法之后:

2016421160354111.png (458×101)

执行了query方法之后:

2016421160411590.png (617×92)

执行了delete方法之后:

2016421160429449.png (513×79)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值