浅析 - Android(安卓)ContentProvider用法示例
尊重每个人的付出,转载请点这里: http://blog.csdn.net/hanj456/article/details/52621150
作为Android的四大组件之一,也许你平时开发中根本没有用到过ContentProvider,但你还是需要掌握它的一些基本操作步骤,任何看起来挺复杂的东西拆开来看就那么回事,下面还是先进入我们的“三问三答”环节:
ContentProvider之“三问三答”
问:ContentProvider是什么?
答:Android四大组件之一(Activity ,Service , BroadcastReceiver ,ContentProvider),向我们提供了在不同应用程序之间共享数据的一种机制,统一了应用之间数据访问的方式。
问:ContentProvider的作用?
答:简单来说它的作用就是为不同应用之间存储和获取数据提供了统一的接口,比较常用到的是共享视频,音频,图片,通讯录这些资源。
问:ContentProvider如何使用?
答:因为相比其他三个组件来说它不常用到,而且看到继承ContentProvider需要实现六个方法,很多人一下子被吓到了,其实仔细看会发现除去对数据基本的增删改查和onCreate()外,也就剩下一个getType()没见过的方法,这样分析下来是不是就感觉轻松很多呢?其实要掌握ContentProvider的基本用法主要记住以下四个API的用法就行:
- UriMatcher.match() //主要是对Uri进行匹配;
- ContentResolver.notifyChange() //主要是对数据进行刷新;
- ContentUris.parseId() //主要是对Uri进行解析;
- ContentUris.withAppendedId() //主要是给Uri添加ID
下面我将以一个简单的Demo为例,分解说明使用ContentProvider实现不同应用之间数据 共享操作需要哪些步骤:
有两个应用:应用A(获取操作数据的一方)和应用B(共享数据的一方)
Step1
在应用B中创建数据资源,这里我新建一个sqlite表 students,添加_id , name , age三个字段:
public class DBHelper extends SQLiteOpenHelper { private static SQLiteOpenHelper mInstance; public synchronized static SQLiteOpenHelper getInstance(Context context){ if (mInstance==null){ mInstance = new DBHelper(context,"test.db",null,1); } return mInstance; } private DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE students(_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INTEGER)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }}
Step2
新建一个常量类,提前准备几个需要用到的常量数据
public class Const { public static final String TABLE_NAME = "students"; public static final String AUTHORITY = "com.test.provider2"; public static final class Student implements BaseColumns { public static final String ID = "_id"; public static final String NAME = "name"; public static final String AGE = "age"; public static final Uri DIR_STUDENTS_URI = Uri.parse("content://" + AUTHORITY + "/students"); public static final Uri ITEM_STUDENT_URI = Uri.parse("content://" + AUTHORITY + "/student"); }}
Step3
新建一个ContentProvider子类继承ContentProvider
public class MyProvider extends ContentProvider { private static UriMatcher mMatcher = new UriMatcher(UriMatcher.NO_MATCH); private static final int STUDENTS = 1; private static final int STUDENT = 2; static { mMatcher.addURI(Const.AUTHORITY, "students", STUDENTS); mMatcher.addURI(Const.AUTHORITY, "student/#", STUDENT); } private SQLiteOpenHelper mHelper; private ContentResolver mResolver; @Override public boolean onCreate() { mHelper = DBHelper.getInstance(getContext()); mResolver = getContext().getContentResolver(); return true;//设置为true表示provider创建生效 } @Nullable @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = mHelper.getReadableDatabase(); switch (mMatcher.match(uri)) { case STUDENTS: return db.query(Const.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); case STUDENT: long id = ContentUris.parseId(uri); String condition = Const.Student.ID + "=" + id; if (selection != null && !selection.equals("")) { condition = condition + " and " + selection; } return db.query(Const.TABLE_NAME, projection, condition, selectionArgs, null, null, sortOrder); default: throw new IllegalArgumentException("未知的Uri:" + uri); } } @Nullable @Override public String getType(Uri uri) { switch (mMatcher.match(uri)) { case STUDENTS: return "vnd.android.cursor.dir/com.test.provider2"; //前半部分是规定的写法,表示这是一个查询全部数据的类型,后半部分是自定义的 case STUDENT: return "vnd.android.cursor.item/com.test.provider2";//前半部分是规定的写法,表示这是一个查询单条数据的类型,后半部分是自定义的 default: throw new IllegalArgumentException("未知的Uri:" + uri); } } @Nullable @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mHelper.getWritableDatabase(); if (mMatcher.match(uri) != STUDENTS) { throw new IllegalArgumentException("未知的Uri:" + uri); } long id = db.insert(Const.TABLE_NAME, Const.Student.ID, values); if (id < 0) { throw new SQLiteException("插入数据失败!"); } Uri newUri = ContentUris.withAppendedId(uri, id); mResolver.notifyChange(uri, null); return newUri; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = mHelper.getWritableDatabase(); int deleteNum = -1; switch (mMatcher.match(uri)) { case STUDENTS: deleteNum = db.delete(Const.TABLE_NAME, selection, selectionArgs); break; case STUDENT: long id = ContentUris.parseId(uri); String condition = Const.Student.ID + "=" + id; if (selection != null && !selection.equals("")) { condition = condition + " and " + selection; } deleteNum = db.delete(Const.TABLE_NAME, condition, selectionArgs); break; default: throw new IllegalArgumentException("未知的Uri:" + uri); } mResolver.notifyChange(uri,null); return deleteNum; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = mHelper.getWritableDatabase(); int updateNum = -1; switch (mMatcher.match(uri)) { case STUDENTS: updateNum = db.update(Const.TABLE_NAME, values, selection, selectionArgs); break; case STUDENT: long id = ContentUris.parseId(uri); String condition = Const.Student.ID + "=" + id; if (selection != null && !selection.equals("")) { condition = condition + " and " + selection; } updateNum = db.update(Const.TABLE_NAME, values, condition, selectionArgs); break; default: throw new IllegalArgumentException("未知的Uri:" + uri); } mResolver.notifyChange(uri,null); return updateNum; }}
Step4
在清单文件中配置provider
"com.test.provider2" android:name=".second.MyProvider" android:exported="true"/>//设置为true表示允许对外共享数据
Step5
经过上面5步ContentProvider的基本步骤就算完成了,剩下的就是在应用A中去获取和操作应用B中的数据了,因为要获取应用B中的数据,必须知道ContentProvider中对外提供的字段,也就是应用B中的常量数据,所以最好先把该常量类Const.java 拷贝到应用A中方便使用,应用A中MainActivity 布局文件很简单,就只有四个按钮分别对应:增,删,改,查;
public class MainActivity extends AppCompatActivity { private ContentResolver mResolver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mResolver = getContentResolver(); } public void add(View v){ ContentValues values = new ContentValues(); values.put(Const.Student.NAME,"小明"); values.put(Const.Student.AGE,16); mResolver.insert(Const.Student.DIR_STUDENTS_URI,values); values.put(Const.Student.NAME,"小强"); values.put(Const.Student.AGE,17); mResolver.insert(Const.Student.DIR_STUDENTS_URI,values); Toast.makeText(this,"添加数据成功",Toast.LENGTH_SHORT).show(); } public void update(View v){ ContentValues values = new ContentValues(); values.put(Const.Student.AGE,28); mResolver.update(Const.Student.DIR_STUDENTS_URI,values,"name like ?",new String[]{"小明"}); Toast.makeText(this,"更新数据成功",Toast.LENGTH_SHORT).show(); } public void delete(View v){ mResolver.delete(Const.Student.DIR_STUDENTS_URI,"name like ?",new String[]{"小明"}); Toast.makeText(this,"删除数据成功",Toast.LENGTH_SHORT).show(); } public void query(View v){ Cursor cursor = mResolver.query(Const.Student.DIR_STUDENTS_URI, null, null, null, null); int count = cursor.getCount(); if (count<1){ Toast.makeText(this,"数据为空!",Toast.LENGTH_SHORT).show(); return; } while (cursor.moveToNext()){ String name = cursor.getString(1); String age = cursor.getString(2); Toast.makeText(this,"name="+name+" ,age="+age,Toast.LENGTH_SHORT).show(); } }}
好了,到此应用A通过ContentProvider操作应用B中的数据实验成功,这里我主要是讲使用ContentProvider的基本步骤,至于上面所提到的那几个API的细节大家有兴趣可以花点时间去查看官方文档说明,理清楚思路很重要,很多东西都没有看上去那么难!
更多相关文章
- 【技术直通车】ArcGIS for Android地图控件的5大常见操作
- Android(安卓)Native层开发Camera应用的方法
- Android之Activity的生命周期和Activity间的跳转和数据传递
- android 本地数据库sqlite的封装
- Android的性能优化
- 在Android库中不能使用switch-case语句访问资源ID
- 在代码中获取Android(安卓)theme中的attr属性值
- 数据解析
- Android——操作摄像头、图片合成