您的位置:首页 > 编程语言 > PHP开发

如何自定义一个优雅的ContentProvider

2015-06-02 18:06 691 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qiaoyan0/article/details/46333285 



复制代码
 1 package com.example.providertest;
 2
 3 import android.net.Uri;
 4 import android.provider.BaseColumns;
 5
 6 /**
 7  * 常量类
 8  */
 9 public final class StudentProfile {
10
11     /**
12      * 一般来说 我们的authority都是设置成 我们这个常量类的包名+类名
13      */
14     public static final String AUTHORITY = "com.example.providertest.StudentProfile";
15
16     /**
17      * 注意这个构造函数 是私有的 目的就是让他不能被初始化
18      */
19     private StudentProfile() {
20
21     }
22
23     /**
24      * 实现了这个BaseColumns接口 可以让我们少写几行代码
25      *
26      */
27     public static final class Students implements BaseColumns {
28         /**
29          * 这个类同样也是不能被初始化的
30          */
31         private Students() {
32
33         }
34
35         // 定义我们的表名
36         public static final String TABLE_NAME = "students";
37
38         /**
39          * 下面开始uri的定义
40          */
41
42         // uri的scheme部分 这个部分是固定的写法
43         private static final String SCHEME = "content://";
44
45         // 部分学生
46         private static final String PATH_STUDENTS = "/students";
47
48         // 某一个学生
49         private static final String PATH_STUDENTS_ID = "/students/";
50
51         /**
52          * path这边的第几个值是指的位置 我们设置成第一个位置
53          */
54         public static final int STUDENT_ID_PATH_POSITION = 1;
55
56         // 这个表的基本的uri格式
57         public static final Uri CONTENT_URI = Uri.parse(SCHEME + AUTHORITY
58                 + PATH_STUDENTS);
59         // 某一条数据的基本uri格式 这个通常在自定義的provider的insert方法里面被调用
60         public static final Uri CONTENT_ID_URI_BASE = Uri.parse(SCHEME
61                 + AUTHORITY + PATH_STUDENTS_ID);
62
63         /**
64          * 定义一下我们的mime类型 注意一下mime类型的写法
65          *
66          * 一般都是后面vnd.应用程序的包名.表名
67          */
68
69         // 多行的mime类型
70         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.example.providertest.students";
71         // 单行的mime类型
72         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.com.example.providertest.students";
73
74         /**
75          * 既然provider提供了查询的方法 我们肯定要设置一个默认的排序方式 这里我们就默认让他根据创建的时间 来降序排序
76          */
77         public static final String DEFAULT_SORT_ORDER = "created DESC";
78
79         /**
80          * 下面就是表的列定义了
81          */
82
83         // 学生的名字
84         public static final String COLUMN_NAME_NAME = "name";
85         // 学生的年龄
86         public static final String COLUMN_NAME_AGE = "age";
87         // 学生的学号
88         public static final String COLUMN_NAME_NUMBER = "number";
89         // 这个学生创建的时间
90         public static final String COLUMN_NAME_CREATE_DATE = "created";
91         // 这个学生入库以后修改的时间
92         public static final String COLUMN_NAME_MODIFICATION_DATE = "modified";
93
94     }
95
96 }

复制代码

 

 


复制代码
  1 package com.example.providertest;
  2
  3 import java.util.HashMap;
  4
  5 import android.content.ContentProvider;
  6 import android.content.ContentUris;
  7 import android.content.ContentValues;
  8 import android.content.Context;
  9 import android.content.UriMatcher;
 10 import android.database.Cursor;
 11 import android.database.SQLException;
 12 import android.database.sqlite.SQLiteDatabase;
 13 import android.database.sqlite.SQLiteOpenHelper;
 14 import android.database.sqlite.SQLiteQueryBuilder;
 15 import android.net.Uri;
 16 import android.text.TextUtils;
 17 import android.util.Log;
 18
 19 public class StudentProfileProvider extends ContentProvider {
 20
 21     // tag 打日志用
 22     private static final String TAG = "StudentProfileProvider";
 23
 24     // 数据库的名字
 25     private static final String DATABASE_NAME = "students_info.db";
 26
 27     // 数据库版本号
 28     private static final int DATABASE_VERSION = 1;
 29
 30     /**
 31      * A UriMatcher instance
 32      */
 33     private static final UriMatcher sUriMatcher;
 34
 35     // 匹配成功的返回值 这里代表多行匹配成功
 36     private static final int STUDENTS = 1;
 37
 38     // 匹配成功的返回值 这里代表多单行匹配成功
 39     private static final int STUDENTS_ID = 2;
 40
 41     /**
 42      * 注意看一下这个哈希表 这个哈希表实际上是主要为了SQLiteQueryBuilder这个类的 setProjectionMap这个方法使用的
 43      *
 44      * 他的值的初始化我放在静态代码块里面,这个地方实际上主要是为了多表查询而存在的
 45      *
 46      * 比如你要多表查询的时候 你有2个表 一个表A 一个表B 你join的时候 肯定需要重命名某个表的某个列
 47      *
 48      * 比如你要把表A的 name1 这个列名重命名成 a.name1 那你就可以add一个key value对,key为name1
 49      *
 50      * value 为a.name1 即可。当然咯 如果你不想重命名或者只是单表查询那就只需要吧key 和value
 51      *
 52      * 的值都写成 一样的即可
 53      *
 54      */
 55     private static HashMap<String, String> sStudentsProjectionMap;
 56
 57     // 定义数据库helper.
 58     private DatabaseHelper mOpenHelper;
 59
 60     // 静态代码块执行
 61     static {
 62
 63         // 先构造urimatcher
 64         sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 65
 66         sUriMatcher.addURI(StudentProfile.AUTHORITY, "students", STUDENTS);
 67
 68         // #代表任意数字 *一般代表任意文本
 69         sUriMatcher.addURI(StudentProfile.AUTHORITY, "students/#", STUDENTS_ID);
 70
 71         // 因为我们这里是单表查询 所以这个地方key和value的值都写成固定的就可以了
 72         sStudentsProjectionMap = new HashMap<String, String>();
 73
 74         sStudentsProjectionMap.put(StudentProfile.Students._ID,
 75                 StudentProfile.Students._ID);
 76
 77         sStudentsProjectionMap.put(StudentProfile.Students.COLUMN_NAME_AGE,
 78                 StudentProfile.Students.COLUMN_NAME_AGE);
 79
 80         sStudentsProjectionMap.put(
 81                 StudentProfile.Students.COLUMN_NAME_CREATE_DATE,
 82                 StudentProfile.Students.COLUMN_NAME_CREATE_DATE);
 83
 84         sStudentsProjectionMap.put(
 85                 StudentProfile.Students.COLUMN_NAME_MODIFICATION_DATE,
 86                 StudentProfile.Students.COLUMN_NAME_MODIFICATION_DATE);
 87
 88         sStudentsProjectionMap.put(StudentProfile.Students.COLUMN_NAME_NAME,
 89                 StudentProfile.Students.COLUMN_NAME_NAME);
 90
 91         sStudentsProjectionMap.put(StudentProfile.Students.COLUMN_NAME_NUMBER,
 92                 StudentProfile.Students.COLUMN_NAME_NUMBER);
 93     }
 94
 95     @Override
 96     public boolean onCreate() {
 97         // TODO Auto-generated method stub
 98         mOpenHelper = new DatabaseHelper(getContext());
 99         return true;
100     }
101
102     /**
103      * 对于自定义contentprovider来说CRUD的这几个方法的写法 要尽量保证 代码优美 和 容错性高
104      *
105      */
106
107     @Override
108     public Cursor query(Uri uri, String[] projection, String selection,
109             String[] selectionArgs, String sortOrder) {
110         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
111         qb.setTables(StudentProfile.Students.TABLE_NAME);
112
113         // 先匹配uri
114         switch (sUriMatcher.match(uri)) {
115         // 多行查询
116         case STUDENTS:
117             qb.setProjectionMap(sStudentsProjectionMap);
118             break;
119         // 单行查询
120         case STUDENTS_ID:
121             qb.setProjectionMap(sStudentsProjectionMap);
122             qb.appendWhere(StudentProfile.Students._ID
123                     + "="
124                     + uri.getPathSegments().get(
125                             StudentProfile.Students.STUDENT_ID_PATH_POSITION));
126             break;
127         default:
128             throw new IllegalArgumentException("Unknown uri" + uri);
129         }
130
131         // 如果没有传orderby的值过来 那我们就使用默认的
132         String orderBy;
133         if (TextUtils.isEmpty(sortOrder)) {
134             orderBy = StudentProfile.Students.DEFAULT_SORT_ORDER;
135         } else {
136             // 如果传过来了 就使用传来的值
137             orderBy = sortOrder;
138         }
139
140         // 开始操作数据库
141         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
142
143         Cursor c = qb.query(db, projection, selection, selectionArgs, null,
144                 null, orderBy);
145
146         // 这个地方要解释一下 这句语句的作用,很多人自定义provider的时候 在query方法里面都忘记
147         // 写这句话,有的人写了也不知道这句话是干嘛的,实际上这句话就是给我们的cursor加了一个观察者
148         // 有兴趣的可以看一下sdk里面这个函数的源码,非常简单。那么他的实际作用就是如果返回的cursor
149         // 被用在SimpleCursorAdapter 类似的这种adapter的话,一旦uri所对应的provider数据发生了变化
150         // 那么这个adapter里的数据是会自己变化刷新的。这句话起的就是这个作用 有兴趣的可以自己写代码
151         // 验证一下 如果把这句话删除掉的话 adapter里的数据是不会再uri更新的时候 自动更新的
152         c.setNotificationUri(getContext().getContentResolver(), uri);
153         return c;
154     }
155
156     /**
157      * 这个地方的返回值 一定要和manifest你配置activity的时候data 字段的值相同 不然会报错
158      */
159     @Override
160     public String getType(Uri uri) {
161         switch (sUriMatcher.match(uri)) {
162         case STUDENTS:
163             return StudentProfile.Students.CONTENT_TYPE;
164         case STUDENTS_ID:
165             return StudentProfile.Students.CONTENT_ITEM_TYPE;
166         default:
167             // 注意这个地方记得不匹配的时候抛出异常信息 这样当比人调用失败的时候会知道哪里不对
168             throw new IllegalArgumentException("Unknown uri" + uri);
169         }
170
171     }
172
173     @Override
174     public Uri insert(Uri uri, ContentValues initialValues) {
175
176         if (sUriMatcher.match(uri) != STUDENTS) {
177             throw new IllegalArgumentException("Unknown URI " + uri);
178         }
179
180         ContentValues values;
181
182         if (initialValues != null) {
183             values = new ContentValues(initialValues);
184         } else {
185             values = new ContentValues();
186         }
187
188         // 下面几行代码实际上就是告诉我们对于某些表而言 默认的字段的值 可以在insert里面自己写好
189         // 不要让调用者去手动再做重复劳动,我们应该允许调用者写入最少的字段的值 来完成db的insert
190         // 操作
191         Long now = Long.valueOf(System.currentTimeMillis());
192
193         if (values.containsKey(StudentProfile.Students.COLUMN_NAME_CREATE_DATE) == false) {
194             values.put(StudentProfile.Students.COLUMN_NAME_CREATE_DATE, now);
195         }
196         if (values
197                 .containsKey(StudentProfile.Students.COLUMN_NAME_MODIFICATION_DATE) == false) {
198             values.put(StudentProfile.Students.COLUMN_NAME_MODIFICATION_DATE,
199                     now);
200         }
201
202         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
203
204         long rowId = db.insert(StudentProfile.Students.TABLE_NAME,
205                 StudentProfile.Students.COLUMN_NAME_NAME, values);
206
207         if (rowId > 0) {
208             Uri stuUri = ContentUris.withAppendedId(
209                     StudentProfile.Students.CONTENT_ID_URI_BASE, rowId);
210             // 用于通知所有观察者数据已经改变
211             getContext().getContentResolver().notifyChange(stuUri, null);
212             return stuUri;
213         }
214
215         // 如果插入失败也最好抛出异常 通知调用者
216         throw new SQLException("Failed to insert row into " + uri);
217
218     }
219
220     @Override
221     public int delete(Uri uri, String where, String[] whereArgs) {
222         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
223         String finalWhere;
224
225         int count;
226
227         switch (sUriMatcher.match(uri)) {
228
229         case STUDENTS:
230             count = db.delete(StudentProfile.Students.TABLE_NAME, where,
231                     whereArgs);
232             break;
233
234         case STUDENTS_ID:
235             finalWhere = StudentProfile.Students._ID
236                     + " = "
237                     + uri.getPathSegments().get(
238                             StudentProfile.Students.STUDENT_ID_PATH_POSITION);
239
240             if (where != null) {
241                 finalWhere = finalWhere + " AND " + where;
242             }
243
244             count = db.delete(StudentProfile.Students.TABLE_NAME, finalWhere,
245                     whereArgs);
246             break;
247
248         default:
249             throw new IllegalArgumentException("Unknown URI " + uri);
250         }
251
252         getContext().getContentResolver().notifyChange(uri, null);
253
254         return count;
255     }
256
257     @Override
258     public int update(Uri uri, ContentValues values, String where,
259             String[] whereArgs) {
260         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
261         int count;
262         String finalWhere;
263
264         switch (sUriMatcher.match(uri)) {
265
266         case STUDENTS:
267
268             count = db.update(StudentProfile.Students.TABLE_NAME, values,
269                     where, whereArgs);
270             break;
271
272         case STUDENTS_ID:
273
274             finalWhere = StudentProfile.Students._ID
275                     + " = "
276                     + uri.getPathSegments().get(
277                             StudentProfile.Students.STUDENT_ID_PATH_POSITION);
278
279             if (where != null) {
280                 finalWhere = finalWhere + " AND " + where;
281             }
282
283             count = db.update(StudentProfile.Students.TABLE_NAME, values,
284                     finalWhere, whereArgs);
285             break;
286         default:
287             throw new IllegalArgumentException("Unknown URI " + uri);
288         }
289
290         getContext().getContentResolver().notifyChange(uri, null);
291
292         return count;
293     }
294
295     // 自定义helper
296     static class DatabaseHelper extends SQLiteOpenHelper {
297
298         DatabaseHelper(Context context) {
299             super(context, DATABASE_NAME, null, DATABASE_VERSION);
300         }
301
302         @Override
303         public void onCreate(SQLiteDatabase db) {
304             // TODO Auto-generated method stub
305             db.execSQL("CREATE TABLE " + StudentProfile.Students.TABLE_NAME
306                     + " (" + StudentProfile.Students._ID
307                     + " INTEGER PRIMARY KEY,"
308                     + StudentProfile.Students.COLUMN_NAME_NAME + " TEXT,"
309                     + StudentProfile.Students.COLUMN_NAME_NUMBER + " TEXT,"
310                     + StudentProfile.Students.COLUMN_NAME_AGE + " INTEGER,"
311                     + StudentProfile.Students.COLUMN_NAME_CREATE_DATE
312                     + " INTEGER,"
313                     + StudentProfile.Students.COLUMN_NAME_MODIFICATION_DATE
314                     + " INTEGER" + ");");
315         }
316
317         @Override
318         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
319             // TODO Auto-generated method stub
320             // 数据库升级的时候 这边的代码 不写了,看各自的业务逻辑了,一般建议大家在这个地方多打一些日志
321         }
322
323     }
324 }

复制代码

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: