欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ContentProvider 内容提供器

程序员文章站 2022-07-08 10:42:33
...

ContentProvider(内容提供者)是Android中的四大组件之一。主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自定义的,系统的也就是例如联系人,图片等数据。

内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口。

如果一个应用程序通过内容提供器对数据提供了外部访问接口,那么任何其他的应用程序就都可以对这部分数据进行访问。Android 系统中自带的电话薄, 短信,媒体库等程序都提供了类似的访问接口,这就使的第三方应用程序可以充分地利用这部分数据来实现更好的功能。

ContentProvider
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。

ContentResolver cr = getContentResolver();  

ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。
public Uri insert(Uri uri, ContentValues values) 用于添加数据到指定Uri的ContentProvider中。
public int delete(Uri uri, String selection, String[] selectionArgs) 用于从指定Uri的ContentProvider中删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用于更新指定Uri的ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查询指定Uri的ContentProvider。

android系统管理联系人的URI如下:
ContactsContract.Contacts.CONTENT_URI 管理联系人的Uri
ContactsContract.CommonDataKinds.Phone.CONTENT_URI 管理联系人的电话的Uri
ContactsContract.CommonDataKinds.Email.CONTENT_URI 管理联系人的Email的Uri
Contacts有两个表,分别是rawContact和Data

rawContact记录了用户的id和name:
其中id栏名称为:ContactsContract.Contacts._ID 
name名称栏为ContactContract.Contracts.DISPLAY_NAME
电话信息表的外键id为ContactsContract.CommonDataKinds.Phone.CONTACT_ID
电话号码栏名称为:ContactsContract.CommonDataKinds.Phone.NUMBER

data表中Email地址栏名称为:
ContactsContract.CommonDataKinds.Email.DATA
其外键栏为:ContactsContract.CommonDataKinds.Email.CONTACT_ID

android为多媒体提供的ContentProvider的Uri如下:
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI 存储在sd卡上的音频文件
MediaStore.Audio.Media.INTERNAL_CONTENT_URI 存储在手机内部存储器上的音频文件

MediaStore.Audio.Images.EXTERNAL_CONTENT_URI SD卡上的图片文件内容
MediaStore.Audio.Images.INTERNAL_CONTENT_URI 手机内部存储器上的图片
MediaStore.Audio.Video.EXTERNAL_CONTENT_URI SD卡上的视频
MediaStore.Audio.Video.INTERNAL_CONTENT_URI 手机内部存储器上的视频

访问通讯录

public class MainActivity extends AppCompatActivity {

    ArrayAdapter<String> adapter;

    List<String> contactsList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView contactsView = (ListView) findViewById(R.id.contacts_view);
        adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,contactsList);
        contactsView.setAdapter(adapter);

        if(ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS},1);
        }else{
            readContacts();
        }
    }

    private void readContacts(){
        Cursor cursor = null;
        try{
            //ContactsContract.CommonDataKinds.Phone.CONTENT_URI 管理联系人的电话的Uri。系统已经封装好了
            cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    null,null,null,null);
            if(cursor != null){
                while (cursor.moveToNext()){
                    //获取联系人姓名
                    String displayName = cursor.getString(cursor.getColumnIndex
                            (ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    //获取联系人手机号
                    String number = cursor.getString(cursor.getColumnIndex
                            (ContactsContract.CommonDataKinds.Phone.NUMBER));
                    contactsList.add(displayName + "\n" + number);
                }
                //更新
                adapter.notifyDataSetChanged();
            }
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            if(cursor != null){
                cursor.close();
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode){
            case 1:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    readContacts();
                } else {
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break;
        }
    }
}

ContentProvider 内容提供器





Uri
Uri代表了要操作的Uri指定了将要操作的ContentProvider的数据。它由两部分组成:authority 和 path。
ContentProvider的scheme已经由Android所规定, scheme为:content://
authority:是用于对不同的应用程序作区分,一般为了避免冲突,都会采用程序包名来进行命名。
path:路径。
id:通常定义URI时使用”#”号占位符代替, 使用时替换成对应的数字
content://com.jxn.provider/person/# #代表任意长度的数字
content://com.jxn.provider/person/* *来匹配任意长度的字符

content://com.example.app.provider/table1 表1
content://com.example.app.provider/table2 表2

要操作table1表中id为10的记录,可以构建这样的路径:/table1/10
content://com.example.app.provider/table1/10

Android系统提供了两个用于操作Uri的工具类:UriMatcher 和 ContentUris
UriMatcher
UriMatcher 类主要用于匹配Uri。UtiMatcher中提供了一个addURI()方法,这个方法接受3个参数,可以分别把authority,path,和一个自定义码传进去。这样,当调用UriMatcher的math()方法时,就可以将一个 Uri 对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表的数据了。

UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI("com.example.app.provider","table1",0);
        uriMatcher.addURI("com.example.app.provider","table1/#",1);

Uri是content://com.example.databasetest.provider/book
使用uriMatcher.math(uri)得到的是匹配码是0。
Uri是content://com.example.databasetest.provider/book/#
使用uriMatcher.math(uri)得到的是匹配码是1。

ContentUris类用于为路径加上ID和获取路径的ID

Uri resultUri =  ContentUris.withAppendedId(uri, id)//给Uri加上id  
long id = ContentUris.parseId(uri) //获取id

创建自己的内容提供器

public class MyProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        return 0;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
       return 0;
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }
}
  1. onCreate()
    初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则表示失败。注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供其才会被初始化。

  2. query()
    从内容提供器中查询数据。使用uri参数来确定查询哪张表, projection参数用于确定查询那些列, selection 和 selectionArgs 参数用于约束查询哪些行, sortOrder 参数用于对结果进行排序, 查询的结果存放在Cursor对象中返回。

  3. insert()
    向内容提供器中添加一条数据。使用 uri 参数来确定要添加到的表, 待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URL。

  4. update()
    更新内容提供器中已有的数据。使用 uri 参数来确定更新哪一张表中的数据,新数据保存在values 参数中, selection 和 selectionArgs 参数用于约束更新哪些行,受影响的行数将作为返回值返回。

5.delete()
从内容提供器中删除数据。 使用 uri 参数来确定删除哪一张表中的数据,selection 和 selectionArgs 参数用于约束删除那些行,别删除的行数将作为返回值返回。

  1. getType()
    根据传入的内容URI来返回相应的MIME类型。

实例
创建DatabaseTest工程
MyDatabaseHelper.class

public class MyDatabaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK = "create table Book ("+
            "id integer primary key autoincrement, "+
            "author text, "+
            "price real, "+
            "pages integer, "+
            "name text)";

    private Context mContext;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    public MyDatabaseHelper(Context context, String name) {
        super(context, name, null,1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //执行建表语句
        db.execSQL(CREATE_BOOK);
    }

    //如果想要这个方法执行,就必须更新数据库的版本号
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //如果已经存在这个表则删除
        db.execSQL("drop table if exists Book");
        //重新创建
        onCreate(db);
    }
}

创建一个内容提供器
DatabaseProvider.class

public class DatabaseProvider extends ContentProvider {

    public static final int BOOK_DIR = 0;

    public static final int BOOK_ITEM = 1;

    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, "book", BOOK_DIR);
        uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
    }

    @Override
    public boolean onCreate() {
        dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
        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 BOOK_DIR:
                cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder);
                break;
            default:
                break;
        }
        return cursor;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // 添加数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Uri uriReturn = null;
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
            case BOOK_ITEM:
                long newBookId = db.insert("Book", null, values);
                uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
                break;
            default:
                break;
        }
        return uriReturn;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        // 更新数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int updatedRows = 0;
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
                updatedRows = db.update("Book", values, selection, selectionArgs);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                updatedRows = db.update("Book", values, "id = ?", new String[] { bookId });
                break;
            default:
                break;
        }
        return updatedRows;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // 删除数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int deletedRows = 0;
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
                deletedRows = db.delete("Book", selection, selectionArgs);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
                break;
            default:
                break;
        }
        return deletedRows;
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.book";
            case BOOK_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.book";
        }
        return null;
    }

AndroidMainfest.xml

 <provider
            android:name=".DatabaseProvider"
            android:authorities="com.example.databasetest.provider"
            android:enabled="true"
            android:exported="true">
        </provider>

创建ProviderTest工程
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add To Book"/>

    <Button
        android:id="@+id/query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Query From Book"/>

    <Button
        android:id="@+id/update_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update Book"/>

    <Button
        android:id="@+id/delete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Delete From Book"/>

</LinearLayout>

MainActivity.class

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private String newId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button addData = (Button) findViewById(R.id.add_data);
        Button queryData = (Button) findViewById(R.id.query_data);
        Button updateData = (Button) findViewById(R.id.update_data);
        Button deleteData = (Button) findViewById(R.id.delete_data);
        addData.setOnClickListener(this);
        queryData.setOnClickListener(this);
        updateData.setOnClickListener(this);
        deleteData.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Uri uri = null;
        ContentValues values = new ContentValues();
        switch (view.getId()){
            case R.id.add_data:
                // 添加数据
                uri = Uri.parse("content://com.example.databasetest.provider/book");
                values.clear();
                values.put("name", "A * of Kings");
                values.put("author", "George Martin");
                values.put("pages", 1040);
                values.put("price", 60);
                Uri newUri = getContentResolver().insert(uri, values);
                newId = newUri.getPathSegments().get(1);
                break;
            case R.id.query_data:
                // 查询数据
                uri = Uri.parse("content://com.example.databasetest.provider/book");
                values.clear();
                Cursor cursor = getContentResolver().query(uri, null, null, null, null);
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String name = cursor.getString(cursor. getColumnIndex("name"));
                        String author = cursor.getString(cursor. getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex ("pages"));
                        double price = cursor.getDouble(cursor. getColumnIndex("price"));
                        Log.d("MainActivity", "book name is " + name);
                        Log.d("MainActivity", "book author is " + author);
                        Log.d("MainActivity", "book pages is " + pages);
                        Log.d("MainActivity", "book price is " + price);
                    }
                    cursor.close();
                }
                break;
            case R.id.update_data:
                // 更新数据
                uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
                values.clear();
                values.put("name", "A Storm of Swords");
                values.put("pages", 1216);
                values.put("price", 30);
                getContentResolver().update(uri, values, null, null);
                break;
            case R.id.delete_data:
                // 删除数据
                uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
                values.clear();
                getContentResolver().delete(uri, null, null);
                break;
            default:
                break;
        }
    }
}