您的位置:首页 > 移动开发 > Android开发

android 开发内容提供者详解(1)

2014-05-09 16:14 447 查看
被匹配的时候,就会返回 code 码, URI节点可以精确的匹配字符串, "*" 号匹配任何的字符串 "#" 号只能匹配数字。[比如删除一条记录中 ID 往往是数字]

参数说明

authority : 授权, 就是 AndroidMainifest.xml 中的授权
path : 匹配路径(通常是一个表名)[* 可以作为匹配任意字符的通配符, # 可以作为匹配数字的通配符]。【注意这里如果是单条记录,需要添加 /# 标示符】

5). 查看 content provider 中的 public abstract String getType (Uri uri) 方法

根据给定的 URI 来实现处理 MIME类型的请求, 对于单条记录返回的 MIME 类型是以
vnd.android.cursor.item 开始的, 对于多条记录返回的MIME类型是以vnd.android.cursor.dir/ 开始的. 这个方法可以在多线程环境下被调用。 详细参考Processes
and Threads.


6). 查看 content provider 中 public abstract Uri insert (Uri uri, ContentValues values) 方法

实现这个方法来处理插入一个新行的请求, 在插入后可以友好的调用 notifyChange() 方法。

参数说明:

uri : 这种格式 "content:// URI" 的插入请求[后续会认真的讲解这一部分内容]。 此处不为空
values : 添加到数据库的 ContentValues 类型集合。博客前面章节讲过次内容,详情可以去参考。此处不为空

返回

新插入选项的URI,可以给其他用户去使用。

7). 删除操作
查看 content provider 的 public abstract int delete (Uri uri, String selection, String[] selectionArgs) 方法
实现这个方法主要是用来处理删除一行或者多行的请求操作,实现这个删除操作需要 有 selection 语句,你可以在删除之后调用 notifyDelete() 方法来做友好的提示
实现这个方法还需要在 URI的末尾解析出行的ID,如果一个指定的行被删除之后,例如,客户端在创建SQL语句的时候会通过 content://contacts/people/22 的这个URI,来解析出末尾的ID号,确定删除ID为 22 的这个记录。

参数说明:

URI : 完整的URI路径,包括行ID
selection : 可选项,在删除行的时候适用

返回 :

影响数据库的行数

3. 代码实现

1) actvity_main.xml 程序界面的布局文件, 这里只是定义了5个按钮,不贴出来了

2) DBOpenHelper.java 主要是用来做数据库的创建使用

[java] view
plaincopy

package com.android.contentproviderdemo;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

import android.util.Log;

public class DBOpenHelper extends SQLiteOpenHelper {

private static final String TAG = "DBOpenHelper";

private static String name = "mydb.db";

private static int version = 1; // 初始版本号是一

public DBOpenHelper(Context context) {

super(context, name, null, version);

// TODO Auto-generated constructor stub

}

@Override

public void onCreate(SQLiteDatabase database) {

// TODO Auto-generated method stub

String sql = "create table student (id integer primary key autoincrement, name varchar(64), address varchar(64))";

database.execSQL(sql); //对数据库的表的创建

Log.i(TAG, "ahuier--> SQLite create succeed!");

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

// TODO Auto-generated method stub

}

}

3) StudentProvider.java 也就是本例子中最重要的代码,实现 Content Provider中增删查改的操作

[java] view
plaincopy

package com.android.contentproviderdemo;

import android.content.ContentProvider;

import android.content.ContentUris;

import android.content.ContentValues;

import android.content.UriMatcher;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.net.Uri;

import android.util.Log;

public class StudentProvider extends ContentProvider {

private final String TAG = "StudentProvider";

private DBOpenHelper helper = null;

private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);

/*

* 这里为何要做这种 操作单条记录 或者 操作多条记录的标志位呢?

* 原因是因为 外部程序 操作 ContentProvider 的方法,仅仅只能通过一个 URI 来访问,

* 所以要定义两个标志位来识别外部需要操作的是单条记录还是多条记录 (比如删除单条记录或者删除多条记录)

*/

private static final int STUDENT = 1; // 操作单条记录

private static final int STUDENTS = 2; // 操作多条记录

// 添加对外部的匹配规则

static {

URI_MATCHER.addURI("com.android.contentproviderdemo.StudentProvider",

"student", STUDENTS);

URI_MATCHER.addURI("com.android.contentproviderdemo.StudentProvider",

"student/#", STUDENT);

}

public StudentProvider() {

// TODO Auto-generated constructor stub

}

@Override

public boolean onCreate() {

// 初始化的时候实例化 helper 对象

helper = new DBOpenHelper(getContext());

return true;

}

// query() 方法返回的是一个 Cursor 的游标,详细方法参考 Android API文档

@Override

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,

String sortOrder) {

Cursor cursor = null;

try {

SQLiteDatabase databse = helper.getReadableDatabase();

int flag = URI_MATCHER.match(uri);

switch (flag) {

case STUDENT:

long id = ContentUris.parseId(uri);

String where_value = " id = " + id;

if (selection != null && !selection.equals("")) {

where_value += " and " + selection;

}

// 这边具体查询方式如果有不懂,可以参考前面即将 SQLite的查询。

cursor = databse.query("student", null, where_value, selectionArgs, null, null,

null, null);

break;

case STUDENTS:

cursor = databse.query("student", null, selection, selectionArgs, null, null,

null, null);

break;

}

} catch (Exception e) {

// TODO: handle exception

}

return cursor;

}

/*

* 它的作用是根据URI返回该URI所对应的数据的MIME类型字符串。

* 这个MIME类型字符串的作用是要匹配AndroidManifest.xml文件

* <activity>标签下<intent-filter>标签的子标签<data>的属性 android:mimeType。

* 如果不一致,则会导致对应的Activity无法启动。

*/

@Override

public String getType(Uri uri) {

int flag = URI_MATCHER.match(uri);

switch (flag) {

case STUDENT:

return "vnd.android.cursor.item";

case STUDENTS:

return "vnd.android.cursor.dir/";

}

return null;

}

@Override

public Uri insert(Uri uri, ContentValues values) {

Uri resultUri = null;

/*

* URI_MATCHER.match(uri) 上面已经在定义了匹配规则,所以这里是用外部传过来的URI匹配内部定义好的规则,

* 如果匹配成功则进行操作,反之不进行操作。

*/

int flag = URI_MATCHER.match(uri);

switch (flag) {

case STUDENTS:

SQLiteDatabase database = helper.getWritableDatabase();

// 注意这边我们使用的是数据库的 database.insert()方法,所以要用 withAppendedId()

// 这种方式来返回URI

long id = database.insert("student", null, values); // 插入当前行的行号

resultUri = ContentUris.withAppendedId(uri, id);

break;

}

Log.i(TAG, "ahuier----->" + resultUri.toString());

// 返回新插入选项的URI,可以给其他用户去使用

return resultUri;

}

@Override

public int delete(Uri uri, String selection, String[] selectionArgs) {

int count = -1; // count作为影响数据库的行数

try {

int flag = URI_MATCHER.match(uri);

SQLiteDatabase database = helper.getWritableDatabase();

switch (flag) {

case STUDENT:

/*

* 传递过来的URI的格式:content://com.android.contentproviderdemo.StudentProvider/student/1

* 以下代码其实就是用来构建 SQL 中删除单挑记录的语句

* delete from student where id = ? // id 通过客户端传递过来的。

*/

long id = ContentUris.parseId(uri); // 解析出 URI 末尾的ID号

String where_value = " id = " + id;

if (selection != null && !selection.equals("")) {

where_value += " and " + selection;

}

// 注意这边的count的是SQLite中的delete()方法,返回的是一个影响数据库的数目

count = database.delete("student", where_value, selectionArgs);

break;

case STUDENTS:

// 传递过来的 URI格式:content://com.android.contentproviderdemo.StudentProvider/student

// 删除多条记录

count = database.delete("studuent", selection, selectionArgs);

break;

}

} catch (Exception e) {

// TODO: handle exception

}

return count;

}

// 更新的方法与删除方法类似,读者可以自己去查 Android官方文档

@Override

public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

int count = -1;

try {

// 更新数据库的语句 : update table set name = ?, address = ? where id = ?

SQLiteDatabase database = helper.getWritableDatabase();

long id = ContentUris.parseId(uri);

int flag = URI_MATCHER.match(uri);

switch (flag) {

case STUDENT:

String where_value = " id = " + id;

if (selection != null && !selection.equals("")) {

where_value += " and " + selection;

}

count = database.update("student", values, where_value, selectionArgs);

break;

case STUDENTS:

// TODO 这里一般情况下, 不会去更新全部表格

break;

}

} catch (Exception e) {

// TODO: handle exception

}

return count;

}

}

4) MainActivity.java 界面程序代码,主要是作为 Content Resolver 代码解析者。跨应用操作数据库也可以用这个代码来使用的

[java] view
plaincopy

package com.android.contentproviderdemo;

import android.net.Uri;

import android.os.Bundle;

import android.app.Activity;

import android.content.ContentResolver;

import android.content.ContentValues;

import android.database.Cursor;

import android.util.Log;

import android.view.Menu;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

public class MainActivity extends Activity {

private static final String TAG = "MainActivity";

private Button button1, button2, button3, button4, button5;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initComponent();

// 创建数据库

button1.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

DBOpenHelper helper = new DBOpenHelper(MainActivity.this);

// 调用 getWritableDatabase()或者 getReadableDatabase()其中一个方法将数据库建立

helper.getWritableDatabase();

}

});

// 插入数据

button2.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

MainActivity.this.insert();

}

});

// 删除数据

button3.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

MainActivity.this.delete();

}

});

// 修改数据

button4.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

MainActivity.this.update();

}

});

// 查询数据

button5.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

MainActivity.this.query();

}

});

}

@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;

}

private void initComponent(){

button1 = (Button) findViewById(R.id.button1);

button2 = (Button) findViewById(R.id.button2);

button3 = (Button) findViewById(R.id.button3);

button4 = (Button) findViewById(R.id.button4);

button5 = (Button) findViewById(R.id.button5);

}

private void insert(){

// 访问内容提供者的步骤:

// 1. 需要一个内容解析者

ContentResolver contentResolver = MainActivity.this.getContentResolver();

/*

* URI的构成

* 它是通过 Uri.parse("content://")方法来构成的

* 构成结构是 :"content://" + "授权路径" + "/" + "标识符 "

*/

Uri uri = Uri.parse("content://com.android.contentproviderdemo.StudentProvider/student");

ContentValues values = new ContentValues();

values.put("name", "AHuier");

values.put("address", "XIAMEN");

contentResolver.insert(uri, values);

}

private void delete() {

ContentResolver contentResolver = MainActivity.this.getContentResolver();

// 删除单条记录,如果要删除多行记录 :content://com.android.contentproviderdemo.StudentProvider/student

/*

* 1 表示当前删除 id = 1的这条记录,这个 id = 1 会传递到 StudentProvider 中去匹配URI规则后解析出 ID ,然后对其进行执行SQL的语句

*/

Uri uri = Uri.

parse("content://com.android.contentproviderdemo.StudentProvider/student/1");

contentResolver.delete(uri, null, null);

}

private void update() {

ContentResolver contentResolver = MainActivity.this.getContentResolver();

Uri uri = Uri.

parse("content://com.android.contentproviderdemo.StudentProvider/student/2");

ContentValues values = new ContentValues();

values.put("name", "HUI");

values.put("address", "Beijing");

contentResolver.update(uri, values, null, null);

}

//查询的结果是一个游标,也就是返回的查询记录,查询可能返回一条记录,也可能返回多条记录

private void query() {

ContentResolver contentResolver = MainActivity.this.getContentResolver();

// 查询单条记录 : content://com.android.contentproviderdemo.StudentProvider/student/2

// 查询多条记录 : content://com.android.contentproviderdemo.StudentProvider/student

Uri uri = Uri.parse("content://com.android.contentproviderdemo.StudentProvider/student/2");

// select * from student where id = 2;

Cursor cursor = contentResolver.query(uri, null, null, null, null);

while(cursor.moveToNext()){

Log.i(TAG, "ahuier---->" + cursor.getString(cursor.getColumnIndex("name")));

}

}

}

4. 程序实现结果

1). 程序主界面



2). 往数据插入3个数据





3). 删除 id = 1 的数据



4). 修改 id = 2 的数据



3). 查询 id = 2 的名称



5. 后续

如何来证明其实跨应用进行通信呢?

另外再写一个应用,操作数据库的方式与上述代码的中的 MainActivity.java 方式类似,也是作为 Content Resolver 解析者的使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: