第一行代码-7.3 创建自己的内容提供器
2016-02-22 16:00
417 查看
之前我们为了实现SQLite的功能,需要创建自己的DatabaseHelper类,现在我们也可以定义自己的ContentProvider来实现跨应用访问数据。但是六个方法都要重写。
由于整个MyProvider的实现比较复杂,所以先看代码再解释。在DatabaseTest中创建DatabaseProvider类,注意要把Toast去除掉,因为跨程序访问的时候不能使用Toast。
有几点需要注意的地方:首先是uri.getPathSegments方法,它会把uri权限之后的内容以'/'符号进行分割,并把分割后
的结果放入到一个字符串列表中。根据前面提到的uri的格式,这个列表的第0 个位置存放的就是路径,第1 个位置存放的就是id 了。
然后是getType方法:它是所有的内容提供器都必须提供的一个方法,用于获取Uri 对象所对应的MIME 类型。一个内容URI 所对应的MIME字符串主要由三部分组分,Android 对这三个部分做了如下格式规定:
1. 必须以vnd 开头。
2. 如果内容URI 以路径结尾,则后接android.cursor.dir/,如果内容URI 以id 结尾,
则后接android.cursor.item/。
3. 最后接上vnd.<authority>.<path>。
写完了provider,还要在manifest中注册才可以使用:
最后是uriMatcher里面的方法,涉及到通配符:#的意思是任意长度的数字,*表示任意长度的字符。为什么要用到任意数字的匹配?因为Update和Delete方法都可能要传入行数的参数(也就是id的值),所以需要提取这个数字,就需要在uriMatcher中插入这个匹配。
终于到了最后一步:在其他应用中对DatabaseTest中的数据库操作。创建ProviderTest项目,并修改布局如下:
然后是MainActivity.java:
实现效果:
![](http://img.blog.csdn.net/20160222194904640)
![](http://img.blog.csdn.net/20160222194946344)
总结一下:ContentProvider是建立在数据存储的基础上实现的,只不过在访问另一个应用的数据的时候,需要借助uri访问,uri包括权限和参数(比如id的值),需要注意格式。在数据存储的应用中借助UriMatch判断出要访问的数据是什么。最后要注意getType的格式。
由于整个MyProvider的实现比较复杂,所以先看代码再解释。在DatabaseTest中创建DatabaseProvider类,注意要把Toast去除掉,因为跨程序访问的时候不能使用Toast。
// DatabaseTest-DatabaseProvider.java public class DatabaseProvider extends ContentProvider{ public static final int STUDENT_DIR = 0; public static final int STUDENT_ITEM = 1; public static final int SUBJECT_DIR = 2; public static final int SUBJECT_ITEM = 3; public static final String AUTHORITY = "com.example.databasetest.provider"; private static UriMatcher uriMatcher; private MyDatabaseHelper dbHelper; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR); uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM); uriMatcher.addURI(AUTHORITY, "subject", SUBJECT_DIR); uriMatcher.addURI(AUTHORITY, "subject/#", SUBJECT_ITEM); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int deletedRows = 0; switch (uriMatcher.match(uri)) { case STUDENT_DIR: deletedRows = db.delete("student", selection, selectionArgs); break; case STUDENT_ITEM: String studentId = uri.getPathSegments().get(1); deletedRows = db.delete("student", "id = ?", new String[] {studentId}); break; case SUBJECT_DIR: deletedRows = db.delete("subject", selection, selectionArgs); break; case SUBJECT_ITEM: String subjectId = uri.getPathSegments().get(1); deletedRows = db.delete("subject", "id = ?", new String[] {subjectId}); break; default: break; } return deletedRows; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case STUDENT_DIR: return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.student"; case STUDENT_ITEM: return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.student"; case SUBJECT_DIR: return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.subject"; case SUBJECT_ITEM: return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.subject"; default: break; } return null; } @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = dbHelper.getWritableDatabase(); Uri uriReturn = null; switch (uriMatcher.match(uri)) { case STUDENT_ITEM: long newStudentId = db.insert("student", null, values); uriReturn = Uri.parse("content://"+AUTHORITY+"/student/"+newStudentId); break; case SUBJECT_ITEM: long newSubjectId = db.insert("subject", null, values); uriReturn = Uri.parse("content://"+AUTHORITY+"/student/"+newSubjectId); break; default: break; } return uriReturn; } @Override public boolean onCreate() { dbHelper = new MyDatabaseHelper(getContext(), "student.db", null, 1); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = null; switch (uriMatcher.match(uri)) { case STUDENT_DIR: cursor = db.query("student", projection, selection, selectionArgs, null, null, sortOrder); break; case STUDENT_ITEM: String studentId = uri.getPathSegments().get(1); cursor = db.query("student", projection, "id = ?", new String[] {studentId}, null, null, sortOrder); break; case SUBJECT_DIR: cursor = db.query("subject", projection, selection, selectionArgs, null, null, sortOrder); break; case SUBJECT_ITEM: String subjectId = uri.getPathSegments().get(1); cursor = db.query("subject", projection, "id = ?", new String[] {subjectId}, null, null, sortOrder); break; default:break; } return cursor; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int updatedRows = 0; switch (uriMatcher.match(uri)) { case STUDENT_DIR: updatedRows = db.update("student", values, selection, selectionArgs); break; case STUDENT_ITEM: String studentId = uri.getPathSegments().get(1); updatedRows = db.update("student", values, "id = ?", new String[] {studentId}); break; case SUBJECT_DIR: updatedRows = db.update("subject", values, selection, selectionArgs); break; case SUBJECT_ITEM: String subjectId = uri.getPathSegments().get(1); updatedRows = db.update("subject", values, "id = ?", new String[] {subjectId}); break; default: break; } return updatedRows; } }
有几点需要注意的地方:首先是uri.getPathSegments方法,它会把uri权限之后的内容以'/'符号进行分割,并把分割后
的结果放入到一个字符串列表中。根据前面提到的uri的格式,这个列表的第0 个位置存放的就是路径,第1 个位置存放的就是id 了。
然后是getType方法:它是所有的内容提供器都必须提供的一个方法,用于获取Uri 对象所对应的MIME 类型。一个内容URI 所对应的MIME字符串主要由三部分组分,Android 对这三个部分做了如下格式规定:
1. 必须以vnd 开头。
2. 如果内容URI 以路径结尾,则后接android.cursor.dir/,如果内容URI 以id 结尾,
则后接android.cursor.item/。
3. 最后接上vnd.<authority>.<path>。
写完了provider,还要在manifest中注册才可以使用:
<!-- DatabaseTest manifest --> <provider android:name="com.example.databasetest.DatabaseProvider" android:authorities="com.example.databasetest.databasetest.provider"> </provider>
最后是uriMatcher里面的方法,涉及到通配符:#的意思是任意长度的数字,*表示任意长度的字符。为什么要用到任意数字的匹配?因为Update和Delete方法都可能要传入行数的参数(也就是id的值),所以需要提取这个数字,就需要在uriMatcher中插入这个匹配。
终于到了最后一步:在其他应用中对DatabaseTest中的数据库操作。创建ProviderTest项目,并修改布局如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/insert_button" android:text="插入数据"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/query_button" android:text="遍历数据"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/update_button" android:text="更新数据"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/delete_button" android:text="删除数据"/> </LinearLayout>
然后是MainActivity.java:
public class MainActivity extends Activity implements OnClickListener{ private Button mBInsert; private Button mBUpdate; private Button mBDelete; private Button mBQuery; private String newId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBInsert = (Button) findViewById(R.id.insert_button); mBUpdate = (Button) findViewById(R.id.update_button); mBDelete = (Button) findViewById(R.id.delete_button); mBQuery = (Button) findViewById(R.id.query_button); mBInsert.setOnClickListener(this); mBUpdate.setOnClickListener(this); mBDelete.setOnClickListener(this); mBQuery.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onClick(View view) { Uri uri; ContentValues values; switch (view.getId()) { case R.id.insert_button: // 添加数据 uri = Uri.parse("content://com.example.databasetest.provider/student"); values = new ContentValues(); values.put("no", "23"); values.put("name", "James"); values.put("number", "112233"); Uri newUri = getContentResolver().insert(uri, values); newId = newUri.getPathSegments().get(1); break; case R.id.query_button: // 遍历数据 uri = Uri.parse("content://com.example.databasetest.provider/student"); Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex("name")); String no = cursor.getString(cursor.getColumnIndex("no")); String number = cursor.getString(cursor.getColumnIndex("number")); Log.d("sysu", name); Log.d("sysu", no); Log.d("sysu", number); } cursor.close(); } break; case R.id.update_button: // 更新数据 uri = Uri.parse("content://com.example.databasetest.provider/student/"+newId); values = new ContentValues(); values.put("no", "6"); values.put("name", "James"); values.put("number", "112233"); getContentResolver().update(uri, values, "id = ?", new String[] {newId}); break; case R.id.delete_button: // 删除数据 uri = Uri.parse("content://com.example.databasetest.provider/student/"+newId); getContentResolver().delete(uri, null, null); break; default: break; } } }
实现效果:
总结一下:ContentProvider是建立在数据存储的基础上实现的,只不过在访问另一个应用的数据的时候,需要借助uri访问,uri包括权限和参数(比如id的值),需要注意格式。在数据存储的应用中借助UriMatch判断出要访问的数据是什么。最后要注意getType的格式。
相关文章推荐
- 1030. Travel Plan (30)
- 单例模式
- Python入门-函数的使用到程序的公布安装
- Eclipse中 maven 工程 pom 文件 <execution> 出错
- Qt如何连接MySQL
- C++ template —— 智能指针(十二)
- matlab 判断两个矩阵是否相等
- 【菜鸟学Java】12:代理模式——静态代理怎么玩?
- eclipse创建maven模块工程
- Asp.net后台获取input的值
- 面向对象03-java基础
- Qt浅谈之四十五QSplitter实现自由伸缩滑动窗口
- C++ template —— 类型区分(十一)
- C#中对datatable的操作
- PHP调试的强悍利器之PHPDBG
- Spring工作原理
- C++面向对象编程<六>:Big Three,三个特殊函数
- Eclipse
- java中什么是bridge method(桥接方法)
- Java:单例模式的七种写法