【安卓笔记】内容提供者

在Android应用中,我们可以使用显式消息(Explicit Intent)来直接访问其他应用的Activity,但是这仅限于Activity的范畴;如果需要使用其他应用的数据,还需要用到另外一种组件,这就是所谓的内容提供者(Content Provider)。

1.什么是内容提供者(Content Porviders)?


顾名思义,内容提供者就是Android应用框架提供的应用之间的数据提供和交换方案,它为所有的应用开了一扇窗,应用可以使用它对外提供数据。每个Content Provider类都使用URI(Universal Resource Identifier,通用资源标识符)作为独立的标识,格式如:content://xxx。其他应用程序通过不同的uri访问不同的内容提供者,并获取/操作里面的数据。
官网定义: Content providers负责管理结构化数据的访问,Content providers封装数据并且提供一套定义数据安全的机制。Content providers是一套在不同进程间进行数据访问的接口。Content providers为数据跨进程访问提供了一套安全的访问机制,对数据组织和安全访问提供了可靠的保证。

2.ContentProviders的作用?

Android通过Content Provider来管理数据诸如音频、视频、图片和通讯录等。还可以通过ContentProvider来访问SQLite数据库等。

以下情况下你需要使用Content Providers

1.你想为其他应用程序提供复杂数据或文件;

2.你想允许用户从你的应用程序中拷贝复杂数据到其他的应用中

3.你想使用搜索框架提供自定义的查询建议功能


3.常见的ContentProviders

android API中提供了一系列标准的内容提供者,它们定义在 android.provider包下。读者可以自己查看文档。下图列出了一些标准的内容提供者及其使用场景:


4.创建自己的ContentProviders     

步骤:
    1.写一个类继承    Content Provider抽象类;
    2.创建一个类存放公用常量接口(方便调用/修改,避免硬编码);
    3.定义一个UriMatcher,在这个匹配器中增加一些待匹配的URI及match_code;
    4.实现oncreate方法;
    5.实现getType方法;
    6.实现crud方法;
    7.在清单文件中配置你的content procider;
下面是我们需要实现的方法清单:

oncreate方法中一般用来初始化资源,比如初始化一个数据库工具类sqliteOpenHelper,这个方法会在主线程中执行,所以我们不能在这个方法中写一些耗时的操作,特别是不能获取数据库实例(SqliteDataBase)
清单文件配置content provider:
<provider
   android:name=".provider.LentItemsProvider"
   android:authorities="de.openminds.samples.cpsample.lentitems"
   />
Content uri是什么?
当你想从内容提供者中获取数据时,你必须提供一个访问路径,这个路径就是uri,一个标准的uri如下所示:
content://authority/optionalPath/optionalId
可以看到,这个uri有四个部分,其中前三个部分是必须的:
1.协议名:就是content://,这个是固定的。
2.授权路径:就是authority,这个是访问的根路径,跟域名差不多,在清单文件中配置(provider节点下的android:authorities属性)
3.访问路径:这个路径用于区分你操作的资源(哪张表),以及操作的方式(增删改查),一般以表名/操作名表示。
4.id:这个是可选的,如果你想查询一个特定id的数据,你可以加上这个id。

Content type是什么?
我们需要实现getType方法,这个方法根据访问的uri返回一个特定的mime类型。
如果是请求单条数据,则返回的类型应该是以vnd.android.cursor.item开头的,如果是多条数据,则返回的类型应该是以vnd.android.cursor.dir开头的,这两个量在ContentResovler类中有定义,分是ContentResolver.CURSOR_ITEM_BASE_TYPE,
ContentResolver.CURSOR_DIR_BASE_TYPE。读者可以查看后面的例子。

5.如何获取/操作ContentProviders暴露的数据

在其他应用中可以通过ContentResolver类获取特定内容提供者中的数据,使用context.getContentResolver方法获取ContentResolver实例。resolver也提供了crud方法用于对contentprovider暴露的数据进行增删改查。执行这些方法必须传入一个uri,指定访问路径。系统根据指定路径寻找对应的内容提供者,然后唤醒该内容提供者的进程,内容提供者根据传递的uri找到其中定义的crud方法,在crud方法内部会使用匹配器(urimatcher)匹配uri,然后根据匹配结果执行相应逻辑。(比如你的uri是一个查询的动作,则内容提供者中的query方法会根据uri的路径来判断你要查询的是哪张表,哪个id)。
注意:contentresolver执行查询操作返回的游标cursor使用完毕一定记得需要关闭!内容提供者中的cursor不用关闭。
6.ContentUris类:
这个工具类提供了三个非常好用的方法:
parseId(Uri contentUri);
withAppendedId(Uri uri,long id);
appendId(Builder bulider,long id);
这个类经常和Uri类在一起使用,用于获取uri中的id,或者向uri中增加一个id。具体使用请看下面的例子。
使用示例:
1、常量定义:
package cn.edu.chd.data;
/**
 * @author Rowand jj
 *
 *数据库信息
 */
public interface DB
{
    /**
     * 数据库名
     */
    public static final String DB_NAME = "person.db";
    /**
     * 版本
     */
    public static final int DB_VERSION = 1;
    
    /**
     *数据库表信息
     */
    public interface TableInfo
    {
        public static final String TABLE_NAME = "person";
        /*
         * 字段信息
         * */
        public static final String ID = "id";
        public static final String NAME = "name";
        public static final String ADDRESS = "address";
    }
}
2、SqlitDBHelper:
package cn.edu.chd.sqlite;

import cn.edu.chd.data.DB;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class SqliteDBHelper extends SQLiteOpenHelper
{

    public SqliteDBHelper(Context context)
    {
        super(context,DB.DB_NAME, null,DB.DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db)
    {
        db.execSQL("CREATE TABLE person(id INTEGER PRIMARY KEY autoincrement,name VARCHAR(20),address VARCHAR(20))");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
    }
}
内容提供者定义:
package cn.edu.chd.providers;
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.text.TextUtils;
import cn.edu.chd.sqlite.SqliteDBHelper;
/**
 * @author Rowand jj
 *
 *一个简单的内容提供者示例
 */
public class PersonProviders extends ContentProvider
{
    private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    /*uri授权路径,清单文件中配置*/
    private static final String AUTHORITY = "cn.edu.chd.providers.personprovider";
    
    /*路径*/
    private static final String PATH_INSERT = "insert";
    private static final String PATH_DELETE = "delete";
    private static final String PATH_UPDATE = "update";
    private static final String PATH_QUERY = "query";
    private static final String PATH_QUERY_SINGLE = "query/#";//查询单条记录,#匹配数字
    
    /*匹配码*/
    private static final int CODE_INSERT = 1;
    private static final int CODE_DELETE = 2;
    private static final int CODE_UPDATE = 3;
    private static final int CODE_QUERY = 4;
    private static final int CODE_QUERY_SINGLE = 5;
    
    private static SqliteDBHelper helper = null;
    
    private static final String TABLE = "person";//默认操作的表
    
    static//定义匹配规则
    {
        matcher.addURI(AUTHORITY,PATH_INSERT, CODE_INSERT);
        matcher.addURI(AUTHORITY,PATH_DELETE,CODE_DELETE);
        matcher.addURI(AUTHORITY,PATH_UPDATE,CODE_UPDATE);
        matcher.addURI(AUTHORITY,PATH_QUERY,CODE_QUERY);
        matcher.addURI(AUTHORITY,PATH_QUERY_SINGLE,CODE_QUERY_SINGLE);
    }
    
    @Override
    public boolean onCreate()
    {
        helper = new SqliteDBHelper(this.getContext());//初始化helper
        return true;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder)
    {
        if(matcher.match(uri) == CODE_QUERY)
        {
            SQLiteDatabase db = helper.getReadableDatabase();
            Cursor c = db.query(TABLE, projection, selection, selectionArgs, null, null, sortOrder);
            return c;
        }else if(matcher.match(uri) == CODE_QUERY_SINGLE)
        {
            SQLiteDatabase db = helper.getReadableDatabase();
            long id = ContentUris.parseId(uri);
            String where_value = " id = "+id;
            if(!TextUtils.isEmpty(selection))
            {
                where_value += " and "+selection;
            }
            Cursor c = db.query(TABLE, projection, where_value, selectionArgs, null, null, sortOrder);
            return c;
        }
        else
        {
            throw new RuntimeException("unknown uri");
        }
    }
    @Override
    public String getType(Uri uri)
    {
        int type = matcher.match(uri);
        switch (type)
        {
        case CODE_QUERY:
            return "vnd.android.cursor.dir/"+TABLE;
        case CODE_QUERY_SINGLE:
            return "vnd.android.cursor.item/"+TABLE;
        default:
            break;
        }
        return null;
    }
    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        if(matcher.match(uri) == CODE_INSERT)
        {
            SQLiteDatabase db = helper.getWritableDatabase();
            long id = db.insert(TABLE, null, values);
            return ContentUris.withAppendedId(uri, id);
        }
        else
        {
            throw new RuntimeException("unknown uri");
        }
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs)
    {
        if(matcher.match(uri) == CODE_DELETE)
        {
            SQLiteDatabase db = helper.getWritableDatabase();
            return db.delete(TABLE, selection, selectionArgs);
        }else
        {
            throw new RuntimeException("unknown uri");
        }
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs)
    {
        if(matcher.match(uri) == CODE_UPDATE)
        {
            SQLiteDatabase db = helper.getWritableDatabase();
            return db.update(TABLE, values, selection, selectionArgs);
        }
        else
        {
            throw new RuntimeException("unknown uri");
        }
    }
    
}
使用contentResolver获取数据:
package com.example.test;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;

public class TestPesonProviders
{
    private Context context;
    private static final String AUTHORITY = "cn.edu.chd.providers.personprovider";
    
    private static final String PATH_INSERT = "insert";
    private static final String PATH_DELETE = "delete";
    private static final String PATH_UPDATE = "update";
    private static final String PATH_QUERY = "query";
    
    public TestPesonProviders(Context context)
    {
        this.context = context;
    }
    
    public void testQuery()
    {
        ContentResolver resolver = context.getContentResolver();
        Uri uri = Uri.parse("content://"+AUTHORITY+"/"+PATH_QUERY);
//        uri = ContentUris.withAppendedId(uri, 100);//查找id为100的数据
        Cursor c = resolver.query(uri,null, null, null, null);
        while(c.moveToNext())
        {
            Log.i("query",c.getInt(c.getColumnIndex("id"))+c.getString(c.getColumnIndex("name"))+c.getString(c.getColumnIndex("address")));
        }
        c.close();//cursor用完必须关闭
    }
    
    public void testInsert()
    {
        ContentResolver resolver = context.getContentResolver();
        Uri uri = Uri.parse("content://"+AUTHORITY+"/"+PATH_INSERT);
        ContentValues values = new ContentValues();
        values.put("id", "100");
        values.put("name","jiayou");
        values.put("address","somewhere");
        resolver.insert(uri, values);
    }
    
    public void testUpdate()
    {
        ContentResolver resolver = context.getContentResolver();
        Uri uri = Uri.parse("content://"+AUTHORITY+"/"+PATH_UPDATE);
        ContentValues values = new ContentValues();
        values.put("address","火星");
    
        resolver.update(uri, values, "id = ?", new String[]{"100"});
    }
    
    public void testDelete()
    {
        ContentResolver resolver = context.getContentResolver();
        Uri uri = Uri.parse("content://"+AUTHORITY+"/"+PATH_DELETE);
        resolver.delete(uri, "id = ?", new String[]{100+""});
    }
}





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值