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

第一行代码-7.3 创建自己的内容提供器

2016-02-22 16:00 417 查看
  之前我们为了实现SQLite的功能,需要创建自己的DatabaseHelper类,现在我们也可以定义自己的ContentProvider来实现跨应用访问数据。但是六个方法都要重写。

  由于整个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的格式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: