码迷,mamicode.com
首页 > 移动开发 > 详细

Android组件----内容提供器Content Provider

时间:2016-07-13 17:34:25      阅读:282      评论:0      收藏:0      [点我收藏+]

标签:

内容提供器(Content Provider)主要用于在不同的应用程序之间共享数据,虽然Android提供的文件存储和SharePreferences都可以设置全局读写模式共享数据,但由于安全性问题,已经在Android4.2中被废弃。内容提供器将提供一种安全的数据共享方式。当一个程序通过内容提供器提供了外部访问接口,其他任何程序都可以通过该接口来对这部分数据进行访问,例如:联系人数据,短信数据。


一、访问其他应用程序中的数据

1 . 获得ContentResolver类的实例

对于每一个应用程序,如果想要访问内容提供器中的数据,就必须要借助于ContentResolver类,可以通过Context中的getContentResolver()放法获得该类的实例。

ContentResolver类中提供了类似于SQLite中类似的insert()、delete()、update()、query()等方法实现对数据的增删改查,但是参数与SQLite中的参数略有不同。

注:ContentResolver中的增删改查方法都是不接受表名参数的,而是使用Uri参数代替,这个参数被称为内容URI。

2 . 获得内容URI

内容URI给内容提供器中的参数建立了唯一标识符,它主要由权限路径两部分组成,权限主要是为了区分不同的应用程序,一般使用程序包名。比如:com.example.app.provider。路径则是对同一应用程序中不同的表进行区分,以/+表名的方式接在权限的后面。最后我饿还需要加上协议声明才组成了完整的内容URI。

内容URI标准格式

content://com.example.app.provider/table1

content://com.example.app.provider/table2

3 . 将URI字符串解析为Uri对象

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

4 . 对数据进行增删改查

//插入数据
ContentValues values1 = new ContentValues();
values1.put("column1", "text1");
values1.put("column2", "text2");
getContentResolver().insert(uri, values1);

//删除数据
getContentResolver().delete(uri, "cloumn2=?", new String[]{"1"});

//修改数据
ContentValues values2 = new ContentValues();
values2.put("column1", "t");
getContentResolver().update(uri, values2, "column1 = ? and column2=?", new String[]{"text", "1"});

//查询数据
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
if (cursor != null){
    while (cursor.moveToNext()){
        String column1 = cursor.getString(cursor.getColumnIndex("column1"));
        int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
    }
    cursor.close();
}

上面的操作和SQLite的操作十分类似,只是传入的参数不再是表名,而是解析出来的Uri对象。


下面重点介绍query()中各参数的意义

query方法参数 对应SQL部分 描述
uri from table_name 指定要查询的应用程序下的某一张表
projection select column1,column2 指定查询的列名
selection where column=value 指定where的约束条件
selectionArgs - 为where中的占位符提供具体的值
orderBy order by column1,column2 指定查询结果的排序方式

下面放上一个获取联系人信息的小例子

MainActivity.java中的代码
public class MainActivity extends AppCompatActivity {
    private ListView contactsView;
    private ArrayAdapter<String> adapter;
    private List<String> contactsList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        contactsView = (ListView) findViewById(R.id.contacts_view);
        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactsList);
        contactsView.setAdapter(adapter);
        readContacts();

    }

    private void readContacts() {
        Cursor cursor = null;
        try{
            //查询联系人数据
            cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, 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);
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (cursor != null){
                cursor.close();
            }
        }
    }
}
activity_main.xml文件
<?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">

    <ListView
        android:id="@+id/contacts_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hello World!" />
</LinearLayout>

上面的代码中的Uri对象并不是通过parse()方法解析,是因为官方向我们直接提供了解析好的Uri对象。我们获取到手机联系人姓名和电话号码后简单地显示在了ListView中。


二、创建自己的内容提供器

上面我们使用别人提供的内容提供器来获取其他程序共享的数据,下面我们将创建自己的内容提供器来共享自己应用程序中的数据。下面是基本的步骤

1 . 创建一个类去继承ContentProvider,重写其中的6个抽象方法。

下面简单介绍这6个方法(与SQLite中的方法很类似)

1 . onCreate() ——- 初始化内容提供器的时候调用。通常在这里完成数据库的额创建或升级等操作。返回true表示内容提供器初始化成功,返回false表示失败。

注:只有当有ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化。

2 . query() —–从内容提供器中来查询数据,query方法的参数已经在上面的表格中做了详细说明。

3 . insert() —– 向内容提供器中添加一条数据,使用方法咋在上面的代码中已经有介绍。

4 . update() —– 更新内容提供器中已有的数据。

5 . delete() —– 从内容提供器中删除数据

6 . getType() —– 根据传入的URI来返回响应的MIME类型。

2 . 分析内容URI。

标准的内容URI(以路径结尾,表示期望访问表中的所有数据):

content://com.example.app.provider/table

含有id的内容URI(以id结尾,表示访问表中拥有相应id的数据):

content://com.example.app.provider/table/1

为了下一步准确解析这两种内容URI,我们还必须使用通配符来匹配上面两种模式。

1 . * ——- 表示匹配任意长度的任意字符
2 . # ——- 表示匹配任意长度的数字

//匹配上面第一行内容URI(所有数据)
content://com.example.app.provider/table/*

//匹配上面第二种URI(相应id的数据)
content://com.example.app.provider/table/#

3 . 借助于UriMatcher类实现匹配内容URI。

上面我们已经分析了内容URI,接下来我们借助于UriMatcher类提供的addURI()方法,分别依次传入三个参数(权限、路径,自定义代码(标识))。最后我们再调用UriMatcher的match()方法,传入一个Uri对象,就会返回我们刚刚传入的自定义代码(标识),我们以此来判断调用方想访问数据的意图。

public class MyProvider extends ContentProvider {
  //自定义代码
  public static final int TABLE1_DIR = 0;
  public static final int TABLE1_ITEM = 1;

  private static UriMatcher uriMatcher;
  static {
      uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
      //期望查询所有数据
      uriMatcher.addURI("com.example.app.provider", "table1", TABLE1_DIR);
      //期望查询相应id的数据
      uriMatcher.addURI("com.example.app.provider", "table1/#", TABLE1_ITEM);
  }

  @Nullable
  @Override
  public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
      switch (uriMatcher.match(uri)){
          case TABLE1_DIR:
              //查询所有数据
              break;
          case TABLE1_ITEM:
              //查询单条数据
              break;
          default:
              break;
      }
      return null;
  }
}

上面的代码只是简单演示了在query()方法中的重写,对于insert()、update()、delete()中的重写都是类似的,都是从Uri对象中获得自定义代码,得到访问数据者的意图后写相应的逻辑。

4 . 重写getType()方法。

getType()方法是所有内容提供器都必须提供的一个方法,用于获取Uri对象所对应的MIME类型,一个内容URI所对应的MIME类型字符串有三部分组成。Android做了如下规定:

1 . 必须以vnd开头

2 . 如果内容URI以路径结尾,则后面接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/

3 . 最后接vnd.<权限>.<路径>

//内容URI以路径结尾
vnd.android.cursor.dir/vnd.com.example.app.provider.table1

//内容URI以id结尾
vnd.android.cursor.item/vnd.com.example.app.provider.table1
@Nullable
@Override
public String getType(Uri uri) {
    switch (uriMatcher.match(uri)){
        case TABLE1_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";
        case TABLE1_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";
    }
    return null;
}

从上面的内容我们也会发现,内容提供器之所以可以保证数据的安全性,是因为要想对数据进行增删改查,我们都首先需要匹配到内容URI格式才可以,只要我们不把隐私数据添加进UriMatcher中,我们的隐私数据就不会被访问到。

Android组件----内容提供器Content Provider

标签:

原文地址:http://blog.csdn.net/bingjianit/article/details/51865650

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!