[android] 11_内容提供者

Android 4.0

内容提供者


一、使用ContentProvider(内容提供者)共享数据

ContentProvider android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider 对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。
 
使用ContentProvider对外共享数据的好处是统一了数据的访问方式
当应用需要通过ContentProvider对外共享数据时,第一步需要继承ContentProvider并重写下面方法:
public class PersonContentProvider extends ContentProvider{
   public boolean onCreate()
   public Uri insert(Uri uri, ContentValues values)
   public int delete(Uri uri, String selection, String[] selectionArgs)
   public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
   public String getType(Uri uri)}
第二步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider ContentProvider 采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:
<manifest .... >
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <provider android:name=".PersonContentProvider" android:authorities="cn.itcast.providers.personprovider"/>
    </application>
</manifest>

二、URI 

Uri代表了要操作的数据Uri主要包含了两部分信息:
1需要操作的ContentProvider
2ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
 
ContentProvider(内容提供者)的scheme已经由Android所规定,
a) scheme为:content://
b) 主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
c) 路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
 
要操作person表中id10的记录,可以构建这样的路径:/person/10
要操作person表中id10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
 
当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")

三、UriMatcher类使用介绍

因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符
switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
   case 1
    break;
   case 2
    break;
   default://不匹配
    break;
}
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://cn.itcast.provider.personprovider/person径,返回的匹配码为1

四、ContentUris类使用介绍

ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
1、withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
2、parseId(uri)方法用于从路径中获取ID部分:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10

Android四大组件之一——内容提供者(主动将私有数据暴露出来)(实际开发中,一般不会写这个,以为这个是将私有数据暴露出来的)

<provider
    android:name="com.itheima.db.PersonDBProvider" //一般为当前ContentProvider的类名
    android:authorities="com.itheima.db.personprovider" > //(主机名)一般为当前应用包名.用途名
</provider>

1、用户需要手动将private数据给暴露出来

2、内容提供者query中,cursor对应的数据库不能close()掉

3、Android中所有的URI都是以content://开头

I/ActivityThread(1830): Pub cn.zengfansheng.db.personprovider: cn.zengfansheng.db.PersonDBProvider

 

 

步骤:

1、创建一个类继承ContentProvider

2、在manifest.xml文件中进行配置

provider
    android:name="cn.zengfansheng.db.PersonDBProvider"
    android:authorities="cn.zengfansheng.db.personprovider"
></provider>
3、定义UriMatcher(addUri,参数二path,指向某一张表/操作)
content://主机/path(表名)/操作
UriMatcher放在上面,有提示代码
private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    private static final int INSERT = 1;// 增
    private static final int DELETE = 2;// 删
    private static final int UPDATE = 3;// 改
    private static final int SELECT = 4;// 查
    static {
        matcher.addURI("cn.zengfansheng.db.personprovider""person/insert"INSERT);
        matcher.addURI("cn.zengfansheng.db.personprovider""person/delete"DELETE);
        matcher.addURI("cn.zengfansheng.db.personprovider""person/update"UPDATE);
        matcher.addURI("cn.zengfansheng.db.personprovider""person/select"SELECT);

    }

4、在本应用中为增删改查的操作进行uri匹配,如果匹配成功就放行,没有匹配成功就阻止

public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        int match = matcher.match(uri);
        if (match == PersonDBProvider.SELECT) {
            SQLiteDatabase database = helper.getWritableDatabase();
            Cursor cursor = database.query("person", projection, selection, selectionArgs, nullnull, sortOrder);
            return cursor; // 内容提供者的cursor不能close(),否则为空。
        }else {
            return null;
        }
}

5、另外一个程序,定义内容提供者 ContentResolver resolver = this.getContentResolver();

6、另外一个程序,通过uri和内容提供者定义的匹配uri进行匹配,匹配成功,就可以继续操作

    /**
     * 查询select
     * 
     * @param view
     */
    public void select(View view) {
        //得到内容解析者
        ContentResolver resolver = this.getContentResolver();
        Uri uri = Uri.parse("content://cn.zengfansheng.db.personprovider/person/select");
        Cursor cursor = resolver.query(uri , new String[]{"id","name","phone"}, nullnullnull);
        while (cursor.moveToNext()) {
            int id = cursor.getInt(cursor.getColumnIndex("id"));
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String phone = cursor.getString(cursor.getColumnIndex("phone"));
            Log.i(TAG"id:" + id + "name:" + name + "phone:" + phone);
        }
        cursor.close();
    }

核心代码:

package cn.zengfansheng.db;
 
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;
 
public class PersonDBProvider extends ContentProvider {
 
    private PersonSQLiteOpenHelper helper;
 
    private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    private static final int INSERT = 1;// 增
    private static final int DELETE = 2;// 删
    private static final int UPDATE = 3;// 改
    private static final int SELECT = 4;// 查
    private static final int SELECTONE = 5;// 查询一条数据
 
    static {
        matcher.addURI("cn.zengfansheng.db.personprovider""person/insert"INSERT);
        matcher.addURI("cn.zengfansheng.db.personprovider""person/delete"DELETE);
        matcher.addURI("cn.zengfansheng.db.personprovider""person/update"UPDATE);
        matcher.addURI("cn.zengfansheng.db.personprovider""person/select"SELECT);
        matcher.addURI("cn.zengfansheng.db.personprovider""person/query/#",
                SELECTONE);
    }
 
    // 当内容提供者被创建的时候调用,适合做数据的初始化
    @Override
    public boolean onCreate() {
        helper = new PersonSQLiteOpenHelper(getContext());
        return false;
    }
 
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        int match = matcher.match(uri);
        if (match == PersonDBProvider.SELECT) {
            SQLiteDatabase database = helper.getWritableDatabase();
            Cursor cursor = database.query("person", projection, selection, selectionArgs, nullnull, sortOrder);
            return cursor; // 内容提供者的cursor不能close(),否则为空。
        } else if (match == PersonDBProvider.SELECTONE) { // 查询一个,根据id
            long id = ContentUris.parseId(uri);// content://authority/path/id
            SQLiteDatabase database = helper.getWritableDatabase();
            Cursor cursor = database.query("person", projection, "id=?",new String[]{id+""}, nullnull, sortOrder);
            return cursor; // 内容提供者的cursor不能close(),否则为空。
        }
        return null;
    }
 
    @Override
    public String getType(Uri uri) {
        //The returned MIME type should start with vnd.android.cursor.item for a single record, or vnd.android.cursor.dir/ for multiple items
        if (matcher.match(uri) == SELECT) {
            return "nd.android.cursor.dir/person"// 多条数据
        } else if (matcher.match(uri) == SELECTONE) {
            return "vnd.android.cursor.item/person"// 一条数据
        }
        return null;
    }
 
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        int match = matcher.match(uri);
        if (match == PersonDBProvider.INSERT) {
            SQLiteDatabase database = helper.getWritableDatabase();
            database.insert("person"null, values);
            database.close();
        } else {
            throw new IllegalArgumentException("请求的uri不匹配");
        }
        return null;
    }
 
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int match = matcher.match(uri);
        if (match == PersonDBProvider.DELETE) {
            SQLiteDatabase database = helper.getWritableDatabase();
            database.delete("person", selection, selectionArgs);
            database.close();
        } else {
            throw new IllegalArgumentException("请求的uri不匹配");
        }
        return 0;
    }
 
    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        int match = matcher.match(uri);
        if (match == PersonDBProvider.UPDATE) {
            SQLiteDatabase database = helper.getWritableDatabase();
            database.update("person", values, selection, selectionArgs);
            database.close();
        } else {
            throw new IllegalArgumentException("请求的uri不匹配");
        }
        return 0;
    }
}

另外一个应用

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
 
public class MainActivity extends Activity {
 
    private static final String TAG = "MainActivity";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    /**
     * 1、查询select
     * 
     * @param view
     */
    public void select(View view) {
        //得到内容解析者
        ContentResolver resolver = this.getContentResolver();
        Uri uri = Uri.parse("content://cn.zengfansheng.db.personprovider/person/select");//多条数据
       Uri uri = Uri.parse("content://cn.zengfansheng.db.personprovider/person/query/10");
        Cursor cursor = resolver.query(uri , new String[]{"id","name","phone"}, nullnullnull);
        while (cursor.moveToNext()) {
            int id = cursor.getInt(cursor.getColumnIndex("id"));
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String phone = cursor.getString(cursor.getColumnIndex("phone"));
            Log.i(TAG"id:" + id + "name:" + name + "phone:" + phone);
        }
        cursor.close();
    }
    /**
     * 2、插入数据insert
     * 
     * @param view
     */
    public void insert(View view) {
        ContentResolver resolver = this.getContentResolver();
        ContentValues values = new ContentValues();
        values.put("name""小胜");
        values.put("phone""110");
        Uri url = Uri.parse("content://cn.zengfansheng.db.personprovider/person/insert");
        resolver.insert(url, values);
        Log.i(TAG"插入数据成功");
    }
    /**
     * 3、更新数据update
     * 
     * @param view
     */
    public void update(View view) {
        ContentResolver resolver = this.getContentResolver();
        Uri uri = Uri.parse("content://cn.zengfansheng.db.personprovider/person/update");
        ContentValues values = new ContentValues();
        values.put("phone""1111111111");
        int update = resolver.update(uri, values, "name=?",
                new String[] { "小胜" });
        if (update > 0) {
            Log.i(TAG"更新数据成功");
        }
    }
    /**
     * 4、删除数据delete
     * 
     * @param view
     */
    public void delete(View view) {
        ContentResolver resolver = this.getContentResolver();
        Uri uri = Uri.parse("content://cn.zengfansheng.db.personprovider/person/delete");
        int delete = resolver.delete(uri, "name=?"new String[] { "小胜" });
        if (delete > 0) {
            Log.i(TAG"删除数据成功");
        }

    }