翻看Android源码可以发现,Android一般的代码架构如下:activity,service,receiver----contentProvider------db(file)
也就是说创建数据库保存数据,借助contentprovider对数据进行增删该查,上层利用Android组件进行交互。于是想着给自己新写的项目也添加个contentProvider来学习Android谷歌工程师的高大上,但从未用过contentprovider,这是第一次用,用完之后就发现一个问题
第一,contentprovider实际上就是将数据库的增删改查方法进行一个集成,给外界提供一个接口
第一,contentprovider是方便了应用程序之间(进程间)进行交换数据,如果你的apk的数据不需要与别的进程交换数据,根本无需使用contentprovider
第三,如果是一个程序间进行数据修改,完全可以自己集成一个提供增删改查的方法
所以呢,在你决定使用contentprovider之前先要看看你是否有使用它的必要。在解决问题之前,首先要分析问题,先动脑然后再动手
尽管如此,我还是依旧学习了一些contentprovider的用法,不为用在项目中,只是为了完善自己的知识体系。
既然明白contentProvider只是一个集成了增删改查的类给外界提供一个调用的接口,那么使用的思路,应该也很明确了
首先是创建数据库,自定义一个数据库的帮助类,来创建数据库
public class MyDataOpenHelper extends SQLiteOpenHelper { private String tableName; public MyDataOpenHelper(Context context, String name, int version) { super(context, name, null, version); tableName = name; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + tableName + " (" + "Id integer primary key autoincrement," + CustomProvider.COLUMN_AGE + "," + CustomProvider.COLUME_NAME+ "," + CustomProvider.COLUME_ID + ")"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
创建好数据库后创建一个自定义的provider
public class CustomProvider extends ContentProvider { private SQLiteOpenHelper mDataOpenHelper; private SQLiteDatabase mDB; private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); public static final String AUTHORITY = "customProvider"; private static final int ALL_STUDENT = 0; private static final int STUDENT = 1; private static final int QUERY_BY_ID = 2; private static final int QUERY_BY_AGE = 3; private static final int QUERY_BY_NAME = 4; public static final String TABLE = "student"; public static final String COLUMN_AGE = "age"; public static final String COLUME_NAME = "name"; public static final String COLUME_ID = "student_id"; static { //第一个参数authority为域名:customProvider //第二个参数为路径:student/# //第三个参数为匹配成功后返回的code matcher.addURI( AUTHORITY ,TABLE,ALL_STUDENT); matcher.addURI(AUTHORITY,TABLE + "/#",STUDENT); } @Override public boolean onCreate() { mDataOpenHelper = new MyDataOpenHelper(getContext(),TABLE,1); return false; } @Nullable @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { mDB = mDataOpenHelper.getReadableDatabase(); if (mDB.isOpen()){ switch (matcher.match(uri)){ case ALL_STUDENT: return mDB.query(TABLE,projection,selection,selectionArgs,null,null,sortOrder); case STUDENT: long id = ContentUris.parseId(uri); return mDB.query(TABLE,null,"Id = " + id,selectionArgs,null,null,null); default: break; } mDB.close(); } return null; } @Nullable @Override public String getType(Uri uri) { return null; } @Nullable @Override public Uri insert(Uri uri, ContentValues values) { mDB = mDataOpenHelper.getWritableDatabase(); if (mDB.isOpen()){ long i = mDB.insert(TABLE,null,values); Log.i("fang","i = " + i); mDB.close(); } return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; } }
先分析一下,在这里定义了一个Urimatcher的实例,可以去匹配uri,在这里定义了三种情况
第一种:unknown
第二种:all_student:
第三种:student
自定义了之后去在Androidmanifest中去注册一下,需要声明authority域名属性,与类中的相同
<provider android:authorities="customProvider" android:name=".provider.CustomProvider"/>
也就是说如果程序想使用contentProvide就做这三步准备即可:
第一步,自定义SQLiteOpenHelper,创建表
第二步,自定义provider,集成增删该查方法
第三步,provider是组件,所以要想使用需要在清单配置文件中去配置
这些都做好以后就可以在activity,service,receiver中进行调用了,举个例子
ContentResolver resolver = getContentResolver(); ContentValues values = new ContentValues(); for (int i = 0; i < 2; i++) { values.put(CustomProvider.COLUME_NAME, i); values.put(CustomProvider.COLUMN_AGE, i); resolver.insert(Uri.parse("content://" + CustomProvider.AUTHORITY + "/" + CustomProvider.TABLE), values); }这是往表中插入两条数据,也可以进行数据的查询:
cursor = resolver.query(Uri.parse("content://" + CustomProvider.AUTHORITY + "/" + CustomProvider.TABLE + "/2"), null, null, null, null); List<StudentBean> studentBean = new ArrayList<>(); if (cursor != null) { while(cursor.moveToNext()) { StudentBean student = null; int nameIndex = cursor.getColumnIndexOrThrow(CustomProvider.COLUME_NAME); int ageIndex = cursor.getColumnIndexOrThrow(CustomProvider.COLUMN_AGE); int id = cursor.getColumnIndexOrThrow(CustomProvider.COLUME_ID); String name = cursor.getString(nameIndex); String age = cursor.getString(ageIndex); Log.i("fang",name); Log.i("fang",age); student = new StudentBean(name, age); studentBean.add(student); } cursor.close();
第一:获取一个contentResolver对象:getCOntentResolver()方法
第二:在调用方法是传入一个uri:这个uri拼起来就是content://customProvidr/student/#,也就是content://域名/表名/要查询的列。
可以看到这样集成在每次调用时会超级麻烦,还不如自己集成的,所以如果是一个应用之间数据增删该查,不建议你使用contentProvider
如果看过我以前的博客的可以发现我早在半年前就打算去总结一个contentprovider的用法,但一直拖延着,眼高手低,内心着实羞愧,作为一个程序员,这样的做法很危险,谨以此文鼓励,铭记。
只有使用过才能明白使用环境,使用方法,以及这样做有什么不足。同时也给目前正在看视频只知道动脑或动眼而不愿动手的人一个小小建议