Android学习笔记-内容提供器

内容提供器

  主要用于跨程序共享数据.

01 运行时申请权限

首先在manifest.xml文件中生命权限

<uses-permission android:name="android.permission.CALL_PHONE"/>

点击按钮打电话

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //如果没有授权,则申请授权
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
            //申请授权
            ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE},1);
        }else{
            call();
        }
    }
});

根据授权结果执行操作(重写onRequestPermissionsResult()方法)

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

打电话的代码

//打电话
private void call() {
    try {
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:10086"));
        startActivity(intent);
    }catch (SecurityException e){
        e.printStackTrace();
    }
}

02 访问其他程序中的数据

  ContentProvider的用法一般有两种:

  • 一种是使用现有的ContentProvider读取和操作相应程序中的数据;

  • 另一种是创建自己的ContentProvider,给程序的数据提供外部访问接口

  如果一个应用程序通过ContentProvider对其数据提供了外部访问接口,那么任何其他的应用程序都可以对这部分数据进行访问。

1. ContentResolver的基本用法

  访问ContentProvider中共享的数据,就一定要借助ContentResolver类, 可以通过Context中的getContentResolver()方法获取该类的实例。

  ContentResolver中提供了一系列的方法用于对数据进行增删改查操作,其中

  • insert()方法用于添加数据

  • update()方法用于更新数据

  • delete()方法用于删除数据

  • query()方法用于查询数据

   不同于SQLiteDatabase, ContentResolver中的增删改查方法都是不接收表名参数的,而是使用一个Uri参数代替,这个参数被称为内容URI。,它主要由两部分组成:authority和path

数据库表table1,此时path为/table1
content://com.example.app.provider/table1
content://com.example.app.provider/table2

  定义好uri字符串后将其转成uri对象

Uri uri = Uri.parse("content://com.example.app.provider/table1");

  之后就可以通过下列语句获得数据了

查询语句

Cursor cursor = getContentResolver().query(
    uri,
    projection,
    selection,
    selectionArgs,
    sortOrder
);
query() 方法参数对应SQL部分描述
urifrom table_name指定查询某个应用程序下的某一张表
projectionselect column1, column2指定查询的列名
selectionwhere column = value指定 where 的约束条件
selectionArgs-为 where 中的占位符提供具体的值
sortOrderorder by column1, column2指定查询结果的排序方式

返回结果后

if(cursor != null){
    while(cursor.moveToNext()){
        String column1 = cursor.getString(cursor.getColumnIndex("column1"));
        int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
    }
    cursor.close();
}

插入语句

ContentValues values = new ContentValues();
values.put("column1","text");
values.put("column2",1);
getContentResolver().insert(uri,values);

更新语句

ContentValues values = new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[]{"text","1"});

删除语句

getContentResolver().delete(uri,"column2 = ?", new String[]{"1"});
2. 获取手机联系人

manifest.xml中权限设置

<uses-permission android:name="android.permission.READ_CONTACTS"/>
//绑定listView
//    ArrayAdapter<String> adapter;
//    List<String> contactsList = new ArrayList<>();
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 (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){
    ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1);
}else{
    readContacts();
}

请求授权后

//请求授权后的结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull 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();
            }
    }
}

同意授权后读取联系人

//查询联系人数据
private void readContacts() {
    Cursor cursor = null;
    try{
        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();
        }
    }
}

03 创建自己的内容提供器

  实现跨程序共享数据的功能,可以通过新建一个类去继承ContentProvider的方式来实现。ContentProvider类中有6个抽象方法,我们在使用子类继承它的时候,需要将这6个方法全部重写。

@Override
public boolean onCreate() {
    // TODO: Implement this to initialize your content provider on startup.
    return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
                    String[] selectionArgs, String sortOrder) {
    // TODO: Implement this to handle query requests from clients.
    throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public Uri insert(Uri uri, ContentValues values) {
    // TODO: Implement this to handle requests to insert a new row.
    throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int update(Uri uri, ContentValues values, String selection,
                  String[] selectionArgs) {
    // TODO: Implement this to handle requests to update one or more rows.
    throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    // Implement this to handle requests to delete one or more rows.
    throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String getType(Uri uri) {
    // TODO: Implement this to handle requests for the MIME type of the data
    // at the given URI.
    throw new UnsupportedOperationException("Not yet implemented");
}
  • onCreate()。初始化ContentProvider的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回true表示ContentProvider初始化成功,返回false则表示失败。

  • query()。从ContentProvider中查询数据。uri参数用于确定查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。

  • insert()。向ContentProvider中添加一条数据。uri参数用于确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URI。

  • update()。更新ContentProvider中已有的数据。uri参数用于确定更新哪一张表中的数据,新数据保存在values参数中,selection和selectionArgs参数用于约束更新哪些行,受影响的行数将作为返回值返回。

  • delete()。从ContentProvider中删除数据。uri参数用于确定删除哪一张表中的数据,selectionselectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。

  • getType()。根据传入的内容URI返回相应的MIME类型。可以看到,很多方法里带有uri这个参数,这个参数也正是调用ContentResolver的增删改查方法时传递过来的。而现在我们需要对传入的uri参数进行解析,从中分析出调用方期望访问的表和数据.

04 实现跨程序数据共享

1. 编写提供器

在项目中编写contentProvider,并重写相关方法(调用项目的数据库向外提供数据).

例子如下:

new->other->Content Provider 勾选Exported和Enabled.内容提供器起名为DatabaseProvider. authority起名为com.example.databasetest.provider.(uri中的一部分,contentResolver通过uri找到内容提供器)

public class DatabaseProvider extends ContentProvider {
    //0_01 uriMatcher用于判断用户使用uri查询的是表还是表中的数据,查询的是哪个表,哪个数据.
    public static final int BOOK_DIR = 0;
    public static final int BOOK_ITEM = 1;
    public static final int CATEGORY_DIR = 2;
    public static final int CATEGORY_ITEM = 3;
    //0_02内容提供器的authority
    private static final String AUTHORITY = "com.example.databasetest.provider";
    private static UriMatcher uriMatcher;

    private MyDatabaseHelper dbHelper;

    //0_03向uri匹配器填充内容
    static {
   		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        //查询book所有字段
        uriMatcher.addURI(AUTHORITY,"book",BOOK_DIR);
        //查询book某个字段
        uriMatcher.addURI(AUTHORITY,"book/#",BOOK_ITEM);
        uriMatcher.addURI(AUTHORITY,"category",CATEGORY_DIR);
        uriMatcher.addURI(AUTHORITY,"category",CATEGORY_ITEM);

    }
    public DatabaseProvider() {
    }

    @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) {
        //1自定义uri查询
        //1_01获得数据库
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = null;
        //1_02根据传进来的uri判断contentResolver查询的是什么
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                //查询的是book表
                cursor = db.query("Book",projection,selection,selectionArgs,null,null,sortOrder);
                break;
            case BOOK_ITEM:
                //查询的是book记录
                String bookId = uri.getPathSegments().get(1);
                cursor = db.query("Book",projection,"id = ?",new String[]{bookId},null,null,sortOrder);
                break;
            case CATEGORY_DIR:
                //查询的是category记录
                cursor = db.query("Category",projection,selection,selectionArgs,null,null,sortOrder);
                break;
            case CATEGORY_ITEM:
                //查询的是category记录
                String categoryId = uri.getPathSegments().get(1);
                cursor = db.query("Category",projection,"id = ?",new String[]{categoryId},null,null,sortOrder);
                break;
            default:
                break;
        }
        return cursor;
    }
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        //2自定义uri插入
        //2_01获得数据库
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Uri uriReturn = null;
        //2_02根据传进来的uri判断contentResolver插入的是哪个表
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
            case BOOK_ITEM:
                //插入的是book表
                long newBookId = db.insert("Book",null,values);
                uriReturn = Uri.parse("content://" + AUTHORITY+"/book/" + newBookId);
                break;
            case CATEGORY_DIR:
            case CATEGORY_ITEM:
                //插入的是category表
                long newCategoryId = db.insert("Category",null,values);
                uriReturn = Uri.parse("content://" + AUTHORITY+"/category/" + newCategoryId);
                break;
            default:
                break;
        }
        return uriReturn;
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        //3自定义uri更新
        //3_01获得数据库
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int updateRows = 0;
        //3_02根据传进来的uri判断contentResolver更新的是什么
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                //更新的是book表
                updateRows = db.update("Book",values,selection,selectionArgs);
                break;
            case BOOK_ITEM:
                //更新的是book记录
                String bookId = uri.getPathSegments().get(1);
                updateRows = db.update("Book",values,"id = ?",new String[]{bookId});
                break;
            case CATEGORY_DIR:
                //更新的是category记录
                updateRows = db.update("Category",values,selection,selectionArgs);
                break;
            case CATEGORY_ITEM:
                //查询的是category记录
                String categoryId = uri.getPathSegments().get(1);
                updateRows = db.update("Category",values,"id = ?",new String[]{categoryId});
                break;
            default:
                break;
        }
        return updateRows;
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        //4自定义uri删除
        //4_01获得数据库
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int deletedRows = 0;
        //4_02根据传进来的uri判断contentResolver更新的是什么
        switch (uriMatcher.match(uri)){
            case BOOK_DIR:
                //更新的是book表
                deletedRows = db.delete("Book",selection,selectionArgs);
                break;
            case BOOK_ITEM:
                //删除的是book记录
                String bookId = uri.getPathSegments().get(1);
                deletedRows = db.delete("Book","id = ?",new String[]{bookId});
                break;
            case CATEGORY_DIR:
                //删除的是category记录
                deletedRows = db.delete("Category",selection,selectionArgs);
                break;
            case CATEGORY_ITEM:
                //查询的是category记录
                String categoryId = uri.getPathSegments().get(1);
                deletedRows = db.delete("Category","id = ?",new String[]{categoryId});
                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";
            case CATEGORY_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.category";
            case CATEGORY_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.category";
        }
        return null;
    }
}

在manifest中可以看到provider被注册.

2. 外部访问内容提供器

有些android版本需要在manifest.xml添加(因为运行时会说找不到内容提供器)

    <queries>
        <package android:name="com.example.cphomework2" />

        <!-- 也可以单独指定provider -->
        <!--        <provider android:authorities="com.example.databasetest.provider" />-->
    </queries>

添加数据

Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
ContentValues values = new ContentValues();
values.put("name","A Clash of Kings");
values.put("author","George Martin");
values.put("pages",1040);
values.put("price",22.85);
Uri newUri = getContentResolver().insert(uri,values);
newId =  newUri.getPathSegments().get(1);

删除数据

Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
getContentResolver().delete(uri,null,null);

更新数据

Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
ContentValues values = new ContentValues();
values.put("name","A Clash of Kings update");
values.put("author","George Martin update");
values.put("pages",1240);
values.put("price",24.05);
 getContentResolver().update(uri,values,null,null);

查询数据

Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
Cursor cursor = getContentResolver.query(uri,null,null,null,null);
if(cursor != null){
    while(cursor.moveToNext()){
        String name = cursor.getString(cursor.getColumnIndex("name"));
        //...
        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
        double price = cursor.getDouble(cursor.getColumnIndex("price"));
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值