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

内容提供器(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中,我们的隐私数据就不会被访问到。

时间: 2024-10-06 13:57:07

Android组件----内容提供器Content Provider的相关文章

安卓学习之数据共享、内容提供器Content Provider

内容提供器Content Provider 能够实现不同程序之间内容的共享.安卓提供了这样的一套机制,让一个程序访问另一个程序的数据,同时保证了安全性. 一个程序可以通过内容提供器对其数据提供外部访问接口,这样其它程序就能通过接口来访问数据. ContentResolver 首先我们先介绍这个类.如果想要访问数据提供器中的数据,我们需要借助ContentResolver类.该对象实例可以在Context中调用getContentResolver()方法来获得.ContentResolver中提供

入职小白随笔之Android四大组件——内容提供器详解(Content Provider)

Content Provider 内容提供器简介 内容提供器(Content Provider)主要用于在不同的应用程序之间 实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性,目前,使用内容提供器是Android实现跨程序共享数据的标准方式. 在正式学习内容提供器之前,我们需要先掌握另外一个非常重要的知识--Android运行时权限,因为 在学习内容提供器时,我们会用到这方面的知识.另外运行时权限的知识在以后我们的开发过程中还会经常的涉

android: 通过内容提供器读取系统联系人

读取系统联系人 由于我们之前一直使用的都是模拟器,电话簿里面并没有联系人存在,所以现在需要自 己手动添加几个,以便稍后进行读取.打开电话簿程序,界面如图 7.1 所示. 图   7.1 可以看到,目前电话簿里是没有任何联系人的,我们可以通过点击 Create a new contact按钮来对联系人进行创建.这里就先创建两个联系人吧,分别填入他们的姓名和手机号,如 图 7.2 所示. 图   7.2 这样准备工作就做好了,现在新建一个 ContactsTest 项目,让我们开始动手吧. 首先还是

android第一行代码-9.内容提供器

内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能, 内容提供器包括两部分:使用现有的内容提供器来读取和操作相应程序中的数据跟创建自己的内容提供器给我们程序的数据提供外部访问接口. 1.使用现有的内容提供器来读取和操作相应程序中的数据 想要访问内容提供器中共享的数据,就一定要借助ContentResolver.可以通过 Context 中的 getContentResolver()方法获取到该类的实例.ContentResolver 中提供了一系列的方法

【练习】内容提供器二、创建自己的内容提供器并测试

1.什么是ContentProvider 首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少. ContentProvider为不同的软件之间数据共享,提供统一的接口.也就是说,如果我们想让其他的应用使用我们自己程序内的数据,就可以使用ContentProvider定义一个对外开放的接口,从而使得其他的应用可以使用咱们应用的文件.数据库内存储的信息.当然,自己开发的应用需要给其他应用共享信息的需求可能比较少见,但是在Andro

android学习十二(android的Content Provider(内容提供器)的使用)

文件存储和SharePreference存储以及数据存储一般为了安全,最好用于当前应用程序中访问和存储数据.内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性.目前使用内容提供器是android实现跨程序共享数据的标准方式.内容提供器可以选择只对一部分数据进行共享,从而保证我们的程序中的隐私数据不会有泄漏的风险. 内容提供器的用法一般有两种,一种是使用现有的内容提

android笔记 : Content provider内容提供器

内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能. 内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口. 第一种方法:使用ContentResolver来读取和操作相应程序中的数据 1.用parse方法将内容 URI 字符串解析成 Uri 对象. uri(Uniform Resource identifier)指的是统一资源标识符Uri uri = Uri .

内容提供器(Content Provider)

内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能, 它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性. 目前,使用内容提供器是 Android 实现跨程序共享数据的标准方式. 内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序中的数据,另一种是创建自己的内容提供器给我们程序的数据提供外部访问接口.

Android学习笔记(二十)——自定义内容提供器

//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 如果我们想要实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承 ContentProvider 的方式来创建一个自己的内容提供器: 一.继承ContentProvider的六个方法: ContentProvider 类中有六个抽象方法,我们需要使用子类去继承它,并重写六个方法,我们先来认识这六个类.新建 MyProvider继承自 ContentProvide,代码如下所示: 1 p