Android四大组件之ContentResolver

      在Android平台上,应用程序之间是相对独立的,分别运行在自己的进程中,如果应用程序之间相互共享数据是需要借助ContentResolver类。ContentResolver用于保存和检索数据,应用程序之间可以提供数据的访问操作,ContentResolver是实现程序数据共享的重要途径。

      ContentResolver(内容提供器)主要有两个用法:一.使用现有的内容提供器来读取和操作相应程序中的数据,二.创建自己内容提供器的对外接口(就是通过这个接口来实现外部应用程序共享数据的)。

      在使用ContentResolver之前,需要脑补一下运行时权限,什么是运行时权限,简单的说就是自我保护(应用程序保护用户的隐私信息);记得QQ空间有个设置,并非好友不可访问QQ空间对吧!这是权限,比如,你注册APP成为用户的时候,它是不是有提醒说:你是需要注册一个APP账号还是用手机号码快速注册,如果你是用手机号码注册的,它会给你发一条验证码短信,那请问你希望它给你短信吗?这个权限要开放吗?好,注册好之后,是不是需要完备自己的资料,头像设置一个吧!图片是不是从图库里来选呀!那问题来了,图库这个应用希望别的应用软件来访问它且共享它的资源吗(一般这个权限都是开放的)?在Android6.0之后,权限有了新的变化;当你注册好进入软件应用里面,它会提示你本应用需要访问你的电话薄,拒绝还是同意?本应用需要访问你的媒体库,拒绝还是同意?脑补到这吧!

      使用ContentResolver不复杂,因为,前面学过SQL语句、学过SQLite数据库,ContentResolver和他们的用法一样,ContentResolver同样也提供了对数据的增删改查操作,只是参数不同而已。参数用Uri来代替,称为内容URI,内容URI给内容提供器中的数据建立了唯一标识符,主要由三部分组成:content://包名/表名(数据路径),提示:URI字符串开头必须加上协议声明content://。URI不能直接使用,需要将它解析成Uri对象才可以作为参数传入,调用Uri.parse()方法即可。例:Uri uri= Uri.parse("content://包名/表名(数据路径)")。

     使用ContentResolver要通过Context中的getContentResolver方法获得该类的实例。常用方法如下:

查询:query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder),

uri:指定查询某个应用程序下的某一张表,

projection:指定查询的列名,

selection:指定where的约束条件,

selectionArgs:为where中的占位符提供具体的值,

sortOrder:指定查询结果的排序方式。

插入:insert(Uri uri,ContentValues values)

更新:update(Uri uri,ContentValues values,String selection,String[] selectionArgs)

删除:delete(Uri uri,String selection,String[] selectionArgs)

getType(Uri uri):获取MIME数据类型,  onCreate():创建ContentResolver时调用

ContentResolver用法一:查询系统ContentResolver(查询手机联系人例子)

package com.xhm.demo.myandroidsql;
import android.Manifest;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

public class ContentResolverActivity extends AppCompatActivity {

    ArrayAdapter<String> adapter;
    List<String> contactsList=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_content_resolver);
        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();
        }
    }
    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();//关闭数据连接
            }
        }
    }
    @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(ContentResolverActivity.this,
                            "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }
}

布局:

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

    <ListView
        android:id="@+id/contacts_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </ListView>

</LinearLayout>

记得申请权限:

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

效果图

ContentResolver用法二:创建一个ContentResolver

这里还需要再深入的了解URL:

内容URL的格式主要有两种,1.以路径结尾的表示访问该表中的所有路径,2.以ID结尾的表示访问表中拥有相应ID的数据。

  1. URI代表要操作的数据,由scheme、authorites、path三部分组成  
  2.             eg:  
  3.                 content://com.jxn.provider/person 
  4.                 scheme   |   authorites   | path  
  5.   
  6.         1,schema:表明要访问ContentProvider。固定为:"content://"  
  7.         2,Authority(主机名或授权):定义了是哪个ContentProvider提供这些数据(一般都用当前包名)。  
  8.         3,path:路径,可根据业务逻辑自定义。eg: person、person/insert、person/insert/10等等  
  9.         4,ID:通常定义URI时使用"#"号占位符代替, 使用时替换成对应的数字  
  10.             "content://com.jxn.provider/ table/# 匹配表中任意一行数据内容的URI格式(#代表任意长度的数字)  
  11.             "content://com.jxn.provider/* 匹配任意表的内容RUI格式(*表示匹配任意长度的任意字符  )

Android系统提供了两个用于操作Uri的工具类:UriMatcher 和 ContentUris   

  1. 1,UriMatcher类用于匹配Uri,用法如下:  
  2.               
  3.             第一步:把你需要匹配的Uri路径全部给注册上,如下:  
  4.               
  5.                 //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码  
  6.                 UriMatcher  matcher = new UriMatcher(UriMatcher.NO_MATCH);  
  7.                 //如果match()方法匹配content://com.jxn.provider.personprovider/person路径,返回匹配码为1  
  8.                 matcher.addURI("com.jxn.provider.personprovider", "person", 1);//添加需要匹配uri,如果匹配就会返回匹配码  
  9.                 //如果match()方法匹配content://com.jxn.provider.personprovider/person/230路径,返回匹配码为2  
  10.                 matcher.addURI("com.jxn.provider.personprovider", "person/#", 2);//#号为通配符  
  11.               
  12.             第二步:使用matcher.match(uri)方法对输入的Uri进行匹配,如果匹配成功就返回匹配码  
  13.                 switch (matcher.match(Uri.parse("content://com.jxn.provider.personprovider/person/10"))) {   
  14.                     case 1  
  15.                         // 相应的业务操作  
  16.                         break;  
  17.                     case 2  
  18.                         // 相应的业务操作  
  19.                         break;  
  20.                     default:  
  21.                         // 相应的业务操作  
  22.                         break;  
  23.                 }  
  24.           
  25.         2,ContentUris类用于为路径加上ID和获取路径的ID  
    1.                 给Uri加上id:   ContentUris.withAppendedId(uri, id)   
    2.                 获取id:       ContentUris.parseId(uri)  

注意getType()方法,它是所有的内容提供器都必须提供的一个方法,用于获取Uri对应的MIME数据类型,一个内容RUI所对应的MIME字符串主要由三部分组成:1.必须以vnb开头,2.如果内容RUI以路径结尾,则后接android.cursor.dir/,如果内容RUI以ID结尾,则后接android.cursor.item/,3.后部接上vnb.<authority>.<path>。

 

package com.xhm.demo.myandroidsql;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.Nullable;
/**
 * Created by Dell on 2017/3/31.
 * 一个完整的ContentProvider
 */
public class MyContentResolver extends ContentProvider {
    public static final int TABLE1_DIR=0;
    public static final int TABLE1_ITEM=1;
    public static final int TABLE2_DIR=2;
    public static final int TABLE2_ITEM=3;
    private static UriMatcher uriMatcher;
    static {
        uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR);
        uriMatcher.addURI("com.example.app.provider","table1/#",TABLE1_ITEM);
        uriMatcher.addURI("com.example.app.provider","table2",TABLE2_DIR);
        uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);
    }
    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        switch (uriMatcher.match(uri)){
            case TABLE1_DIR:
                //查询table1表中的所有数据
                break;
            case TABLE1_ITEM:
                //查询table1表中的单条数据
                break;
            case TABLE2_DIR:
                //查询table2表中的所有数据
                break;
            case TABLE2_ITEM:
                //查询table2表中的单条数据
                break;
            default:
                break;
        }
        return null;
    }

    @Nullable
    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)){
            case TABLE1_DIR:
                return "vnd.android.cursor.dir/vnb.com.example.app.provider.table1";
            case TABLE1_ITEM:
                return "vnd.android.cursor.item/vnb.com.example.app.provider.table1";
            case TABLE2_DIR:
                return "vnd.android.cursor.dir/vnb.com.example.app.provider.table2";
            case TABLE2_ITEM:
                return "vnd.android.cursor.item/vnb.com.example.app.provider.table2";
            default:
                break;
        }
        return null;
    }

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

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

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

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值