//此系列博文是《第一行Android代码》的学习笔记,如有错漏,欢迎指正!

  内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性。当一个应用程序通过内容提供器对其数据提供了外部访问接口,任何其他的应用程序就都可以对这部分数据进行访问。Android 系统中自带的电话簿、短信、媒体库等程序都提供了类似的访问接口,这就使得第三方应用程序可以充分地利用这部分数据来实现更好的功能。

一、ContentResolver 的基本用法

  对于每一个应用程序来说,如果想要访问内容提供器中共享的数据,就一定要借助ContentResolve 类——通过 Context 中的 getContentResolver()方法获取到该类的实例。ContentResolver 中提供了一系列的方法用于对数据进行 CRUD 操作,这些操作与SQL相似,不过在方法参数上有点区别:与SQL相比,ContentResolver 中的增删改查方法都是不接收表名参数的,而是使用一个 Uri参数代替,这个参数被称为内容 URI。内容 URI给内容提供器中的数据建立了唯一标识符,它主要由两部分组成:

  1)权限(authority):用于对不同的应用程序做区分的,一般为了避免冲突,都会采用程序包名的方式来进行命名。比如某个程序的包名是 com.example.app,那么该程序对应的权限就可以命名为 com.example.app.provider;

  2)路径(path):用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。比如某个程序的数据库里存在两张表,table1和 table2,这时就可以将路径分别命名为/table1和/table2。

  把权限和路径进行组合,内容 URI 就变成了 com.example.app.provider/table1和 com.example.app.provider/table2。不过,目前还很难辨认出这两个字符串就是两个内容URI,我们还需要在字符串的头部加上协议声明。因此,内容 URI最标准的格式写法如下:
  content://com.example.app.provider/table1
  content://com.example.app.provider/table2

  在得到了内容 URI字符串之后,我们还需要将它解析成 Uri 对象才可以作为参数传入。解析的方法也相当简单,代码如下所示:

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

  只需要调用 Uri.parse()方法,就可以将内容 URI字符串解析成 Uri 对象了。现在我们就可以使用这个 Uri对象来进行CRUD操作:

  (1)查询数据:

  若想查询table1 表中的数据,代码如下所示:

 Cursor cursor = getContentResolver().query(
     uri, //指定查询某个应用程序下的某一张表
     projection, //指定查询的列名
     selection, //指定 where 的约束条件
     selectionArgs, //为 where中的占位符提供具体的值
     sortOrder //指定查询结果的排序方式
 );

  查询完成后返回的仍然是一个 Cursor 对象,这时我们就可以将数据从 Cursor 对象中逐个读取出来了。 读取的思路仍然是通过移动游标的位置来遍历 Cursor 的所有行, 然后再取出每一行中相应列的数据,代码如下所示:

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

  (2)添加数据:

  将待添加的数据组装到 ContentValues 中,然后调用 ContentResolver的 insert()方法,将 Uri 和 ContentValues作为参数传入即可。

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

  (3)更新数据:
  如果我们想要更新这条新添加的数据,把 column1 的值清空,可以借助ContentResolver 的 update()方法实现,代码如下所示:

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

 (4)删除数据:

  我们可以调用 ContentResolver 的 delete()方法将刚才数据删除掉,代码如下所示:

 getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

  初步认识了CRUD操作后,我们来实践一下。

二、实践:读取联系人:

  先确保手机里有联系人,然后新建一个project:ContactsTest.

  (1)设置布局文件

 <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" >
     </ListView>
 </LinearLayout>

  在LinearLayout 里我们放置了一个 ListView,用于显示联系人。

  (2)修改主活动代码:

 public class MainActivity extends AppCompatActivity {

     ListView contactsView;
     ArrayAdapter<String> adapter;
     List<String> contactsList = new ArrayList<String>();
     @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();
             }
         }
     }
 }

  在 onCreate()方法中,我们首先获取了 ListView控件的实例,并给它设置好了适配器,然后就去调用 readContacts()方法。在readContacts()方法中,我们使用了 ContentResolver 的 query()方法来查询系统的联系人数据。 不过传入的 Uri参数显得有些奇怪,为什么没有调用 Uri.parse()方法去解析一个内容 URI 字符串呢?这是因为ContactsContract.CommonDataKinds.Phone类已经帮我们做好了封装, 提供了一个CONTENT_URI常量,这个常量就是使用 Uri.parse()方法解析后的结果。接着我们历遍 Cursor 对象读取数据,联系人姓名这一列对应常量为ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,联系人手机号这一列对应的常量是 ContactsContract.CommonDataKinds.Phone.NUMBER。两个数据都取出之后,将它们进行拼接,并且中间加上换行符,然后将拼接后的数据添加到 ListView 里。最后千万不要忘记将 Cursor 对象关闭掉。

  (3)修改权限:
  读取系统联系人也是需要声明权限的,因此修改AndroidManifest.xml 中的代码,如下所示:

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.mycompany.contactstest" >
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <application
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
         android:supportsRtl="true"
         android:theme="@style/AppTheme" >

         <activity android:name=".MainActivity" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />

                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
     </application>

 </manifest>

  现在便可以成功地运行程序了。

  //End.

Android学习笔记(十九)——内容提供器的更多相关文章

  1. 《第一行代码》学习笔记30-内容提供器Content Provider(3)

    1."如何在自己的程序中访问其他应用程序的数据",思路->获取到该应用程序的内容URI,再借助ContentResolver进行CRUD操作. 2.要实现跨程序共享数据-&g ...

  2. 《第一行代码》学习笔记28-内容提供器Content Provider(1)

    1.内容提供器:用于在不同的应用程序之间实现数据共享的功能,提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问 数据的安全性.使用内容提供器是Android实现跨程序共享数据 ...

  3. 《第一行代码》学习笔记29-内容提供器Content Provider(2)

    1.查询操作: if (cursor != null) { while (cusor.moveToNext()) { String column1 = cursor.getString(cursor. ...

  4. Android入门(十四)内容提供器-实现跨程序共享实例

    原文链接:http://www.orlion.ga/661/ 打开SQLite博文中创建的 DatabaseDemo项目,首先将 MyDatabaseHelper中使用 Toast弹出创建数据库成功的 ...

  5. Android学习笔记(九)——布局和控件的自定义

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! View是 Android中一种最基本的 UI组件,它可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件 ...

  6. python 学习笔记十九 django深入学习四 cookie,session

    缓存 一个动态网站的基本权衡点就是,它是动态的. 每次用户请求一个页面,Web服务器将进行所有涵盖数据库查询到模版渲染到业务逻辑的请求,用来创建浏览者需要的页面.当程序访问量大时,耗时必然会更加明显, ...

  7. Android学习笔记(九) 视图的应用布局效果

    最近少了写博客,可能最近忙吧,工作上忙,因为工作原因也忙于学习,也没记录什么了,也没有按照之前的计划去学习了.现在就记录一下最近学到的. 要做Android应用,界面设计少不了,可惜之前一直在用Win ...

  8. android 学习随笔十九(对话框、样式、主题、国际化 )

    1.对话框 package com.itheima.dialog; import android.os.Bundle; import android.app.Activity; import andr ...

  9. android学习笔记十——TabHost

    TabHost——标签页 ==> TabHost,可以在窗口放置多个标签页,每个标签页相当于获得了一个与外部容器相同大小的组件摆放区域. 通过此种方式可以实现在一个容器放置更多组件(EG:通话记 ...

  10. Java基础学习笔记十九 IO

    File IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再 ...

随机推荐

  1. WCF自动添加消息头

    客户端自定义消息查看器实现IClientMessageInspector接口在消息发送之前添加消息头 class ClientMessageInspector : System.ServiceMode ...

  2. 1125MySQL Sending data导致查询很慢的问题详细分析

    -- 问题1 tablename使用主键索引反而比idx_ref_id慢的原因EXPLAIN SELECT SQL_NO_CACHE COUNT(id) FROM dbname.tbname FORC ...

  3. 一段可以清理NSArray中的空对象的代码(递归)

    - (NSArray *)clearAllNullObject{ NSMutableArray *array = [self mutableCopy]; ;i < array.count;i++ ...

  4. 使用tmpfs作为缓存加速缓存的文件目录

    使用tmpfs作为缓存加速缓存的文件目录 [root@web02 ~]# mount -t tmpfs tmpfs /dev/shm -o size=256m[root@web02 ~]# mount ...

  5. 通过js的console优雅的将php调试信息输出

    function consoleLog($val){ $debug = debug_backtrace(); unset($debug[0]['args']); echo '<script> ...

  6. rabbitmq消息队列——&quot;发布订阅&quot;

    三."发布订阅" 上一节的练习中我们创建了一个工作队列.队列中的每条消息都会被发送至一个工作进程.这节,我们将做些完全不同的事情--我们将发送单个消息发送至多个消费者.这种模式就是 ...

  7. Android学习系列(41)--Android Studio简单使用

    1. 环境 UBUNTU 14.04 + Android Studio 0.8.2 2. 安装jdk openjdk-7是一个很好的选择: sudo apt-get update sudo apt-g ...

  8. 01背包问题:Charm Bracelet (POJ 3624)(外加一个常数的优化)

    Charm Bracelet    POJ 3624 就是一道典型的01背包问题: #include<iostream> #include<stdio.h> #include& ...

  9. mongodb学习6--js操作mongodb

    一,mongo知识储备:1. 获取mongoDB中数据库的大小命令use databasenamedb.stats()显示信息如下 > db.stats() { "collection ...

  10. hibernate manytoone中的lazy EAGER

    Hibernate中的字段映射中的Fetch有两种方式:EAGER和LAZY Eager:全部抓取 Lazy:延迟抓取 如果在字段中声明为Eager,那么在取得当前Bean时,同时会抓取Bean中的关 ...