分类:C#、Android、VS2015;

创建日期:2016-03-08

一、简介

ContentProvider:内容提供程序。

Android的ContentProvider与.NET框架的EF(Entity Framework)非常类似。在EF中,每个类表示数据库中的一个表,类中的每个属性对应表的字段,类的每个实例表示数据库表的一行记录。同样,在Android中,每个ContentProvider类的实例表示数据表的一行记录,ContentProvider实例集合中的每一项表示数据表中的一列。

另外,Entity Framework的数据源不一定是数据库,也可以是其他类型的数据。同样,Android的ContentProvider可访问的数据源也不一定是数据库,也一样可以是其他类型的数据。而且EF和ContentProvider也都提供了对数据源的CRUD(Create、Read、Update、Delete)操作。

可将ContentProvider理解为在不同的进程之间实现数据交互或数据共享的工具。换言之,利用ContentProviders,可访问由其他应用程序公开的数据,比如访问Android的系统数据(如联系人、媒体和日历信息)、SQLite数据库、文件等。

1、安卓内置的内容提供程序(Built-In Providers)

安卓内置的所有Provide都在Android.Provider命名空间下,这些类有:

  • Android.Provider.Browser类–浏览书签的历史记录(此操作需要READ_HISTORY_BOOKMARKS或WRITE_HISTORY_BOOKMARKS权限)。
  • Android.Provider.CallLog类 –通话记录。查看最近拨出或收到的电话。
  • Android.Provider.ContactsContract类 –联系人。查看用户的联系人名单,包括姓名、电话、照片等信息。
  • Android.Provider.MediaStore类 –媒体存储。查看设备上用户存储的媒体文件,包括音频、图像、视频等。
  • Android.Provider.Settings类 –系统设置和首选项。
  • Android.Provider.UserDictionary类 –用于预测文本输入的用户定义的字典。
  • Android.Provider.VoicemailContract类 –语音信箱中的联系人及其历史记录。

安卓内置的所有Provide实际上都是通过ContentProvider来操作的,只是它封装以后你看不到ContentProvider了,换言之,你直接使用它对ContentProvider进一步封装后的这些类就行了,这样用起来更方便些。

2、如何使用这些内置的提供程序

使用ContentProvider的首选方式是利用LoaderManager中的CursorLoader类得到ContentProvider的实例。,这种方式实际上是通过先关闭主线程然后再利用数据绑定来加载数据的。得到ContentProviders的实例以后,就可以通过CursorAdapters将ContentProviders加载的数据显示出来。

前面刚刚说过,由于Android对ContentProvider做了进一步的封装,因此在代码中访问Android系统通过ContentProvider公开的数据时,它实际是使用ContentProvider类来处理它的,只是你看不到它是这样做的而已。换言之,对于开发人员来说,它对其封装以后,要求你先通过Uri创建一个游标(cursor),然后再利用这个cursor对象访问它公开的数据。

下面以android.provider.ContactsContract类为例说明Uri的含义和用法,Built-In Providers中其他类的用法与此相似。

Uri实际上就是把DNS颠倒过来写的一个字符串,例如:

com.android.contacts/data

为了不让开发人员耗费精力去理解和记住这个原始字符串,Android的Contacts(联系人)提供程序在android.provider.ContactsContract类中又以常量的形式公开了这些元数据,你只需要通过这些常量,即可得到ContentProvider的Uri、可查询的表名以及列名。

有3种通过Uri创建游标(cursor)的方式:

  • CursorLoader().LoadInBackground() –这是首选方式,是从Android 3.0 (API Level 11)开始引入的处理办法。由于CursorLoader是通过后台线程查询ContentResolver的,因此该方法不会引起界面阻塞,而且不用时还能自动关闭它。另外,如果你希望在比Android 3.0更低的版本中使用这个类,可通过v4兼容库(v4 compatibility library)来访问。
  • ContentResolver.Query() –使用这种办法得到cursor对象后,不用时必须调用cursor.Close()关闭它,否则就会引起内存泄漏。
  • ManagedQuery() –这是Android 2.3 (API Level 10) 及更早版本中提供的方法。注意该方法在 Android 3.0 (API 级别 11) 中就已经被标记为已过时,因此不要再使用它。

在Android公开的这些方法中,不论使用哪种方式,都需要提供以下几个基本参数:

  • Uri –内容的完全限定名称。
  • Projection – 投影。其作用是为cursor指定选择的一列或多列。
  • Selection – 其作用类似于SQL的WHERE子句。
  • SelectionArgs – 用参数替换WHERE子句中所选的内容。
  • SortOrder – 指定排序的列。

再次强调一下,CursorLoader是使用ContentProvider的首选方式。

3、自定义ContentProvider

除了上面介绍的Android内置的Provider外,你还可以创建自定义的Provider。数据库一章中已经介绍过其用法了,这里不再重复。

二、例19-3—用CursorLoader读取和更新通讯录

这一节仍以读取和更新通讯录为例,演示CursorLoader的基本用法。该例子是在【12.5利用Intent读取和更新通讯录】例子的基础上改进的,在这个该例子中,除了像例12-4那样显示出联系人外,如果通讯录中你输入了联系人的照片,还能把对应的照片显示出来。如果你没有在通讯录中输入照片,就用默认的照片来代替。

1、运行截图

由于是例子,所以截图中的通讯录照片是随便选的一个图。

2、设计步骤

(1)该例子需要的权限

由于前面章节的例子已经添加过这些权限,所以不需要再添加了。如果你单独创建一个项目,必须添加下面的权限。

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

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

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

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

(2)添加ch1903_contact_picture.png

在drawable文件夹下添加该文件。用于找不到联系人照片时显示的替换照片。

(3)添加ch1903ContactListItem.xml

在layout文件夹下添加该文件。

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <ImageView
  6. android:id="@+id/ch1903_ContactImage"
  7. android:layout_width="50dp"
  8. android:layout_height="50dp"
  9. android:layout_margin="5dp" />
  10. <TextView
  11. android:id="@+id/ch1903_ContactName"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:textAppearance="?android:attr/textAppearanceLarge"
  15. android:layout_marginLeft="5dp" />
  16. </LinearLayout>

(4)添加ch1903Main.axml

在layout文件夹下添加该文件。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent">
  6. <ListView
  7. android:id="@+id/ch1903_ContactsListView"
  8. android:layout_width="fill_parent"
  9. android:layout_height="fill_parent" />
  10. </LinearLayout>

(5)添加ch1903MainActivity.cs

在SrcDemos文件夹下添加该文件。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. using Android.App;
  7. using Android.Content;
  8. using Android.OS;
  9. using Android.Runtime;
  10. using Android.Views;
  11. using Android.Widget;
  12. using Android.Provider;
  13. using Android.Database;
  14.  
  15. namespace MyDemos.SrcDemos
  16. {
  17. [IntentFilter(new[] { Intent.ActionMain }, Categories = new[] { ch.MyDemosCategory })]
  18. [Activity(Label = "【例19-3】ContentProvider基本用法")]
  19. public class ch1903MainActivity : Activity
  20. {
  21. protected override void OnCreate(Bundle savedInstanceState)
  22. {
  23. base.OnCreate(savedInstanceState);
  24. SetContentView(Resource.Layout.ch1903Main);
  25. var contactsAdapter = new ContactsAdapter(this);
  26. var contactsListView = FindViewById<ListView>(Resource.Id.ch1903_ContactsListView);
  27. contactsListView.Adapter = contactsAdapter;
  28. }
  29. }
  30.  
  31. public class ContactsAdapter : BaseAdapter<ch1903Contact>
  32. {
  33. List<ch1903Contact> contactList;
  34. Activity activity;
  35.  
  36. public override int Count
  37. {
  38. get { return contactList.Count; }
  39. }
  40.  
  41. public override ch1903Contact this[int position]
  42. {
  43. get { return contactList[position]; }
  44. }
  45.  
  46. public ContactsAdapter(Activity activity)
  47. {
  48. this.activity = activity;
  49. FillContacts();
  50. }
  51.  
  52. public override long GetItemId(int position)
  53. {
  54. return contactList[position].Id;
  55. }
  56.  
  57. public override View GetView(int position, View convertView, ViewGroup parent)
  58. {
  59. var view = convertView ?? activity.LayoutInflater.Inflate(Resource.Layout.ch1903ContactListItem, parent, false);
  60. var contactName = view.FindViewById<TextView>(Resource.Id.ch1903_ContactName);
  61. var contactImage = view.FindViewById<ImageView>(Resource.Id.ch1903_ContactImage);
  62. contactName.Text = contactList[position].DisplayName;
  63. if (contactList[position].PhotoId == null)
  64. {
  65. contactImage = view.FindViewById<ImageView>(Resource.Id.ch1903_ContactImage);
  66. contactImage.SetImageResource(Resource.Drawable.ch1903_contact_picture);
  67. }
  68. else
  69. {
  70. var contactUri = ContentUris.WithAppendedId(ContactsContract.Contacts.ContentUri, contactList[position].Id);
  71. var contactPhotoUri = Android.Net.Uri.WithAppendedPath(contactUri, ContactsContract.Contacts.Photo.ContentDirectory);
  72. contactImage.SetImageURI(contactPhotoUri);
  73. }
  74. return view;
  75. }
  76.  
  77. private void FillContacts()
  78. {
  79. var uri = ContactsContract.Contacts.ContentUri;
  80. string[] projection = {
  81. ContactsContract.Contacts.InterfaceConsts.Id,
  82. ContactsContract.Contacts.InterfaceConsts.DisplayName,
  83. ContactsContract.Contacts.InterfaceConsts.PhotoId
  84. };
  85.  
  86. // 下面这条语句已过时,不要使用它
  87. //var cursor = activity.ManagedQuery (uri, projection, null, null, null);
  88.  
  89. // 如果用下面这条语句,不用时必须调用cursor.Close()关闭它
  90. //var cursor = activity.ContentResolver.Query(uri, projection, null, null, null);
  91.  
  92. // 下面是建议的用法
  93. var loader = new CursorLoader(activity, uri, projection, null, null, null);
  94. var cursor = (ICursor)loader.LoadInBackground();
  95. contactList = new List<ch1903Contact>();
  96. if (cursor.MoveToFirst())
  97. {
  98. do
  99. {
  100. contactList.Add(new ch1903Contact
  101. {
  102. Id = cursor.GetLong(cursor.GetColumnIndex(projection[0])),
  103. DisplayName = cursor.GetString(cursor.GetColumnIndex(projection[1])),
  104. PhotoId = cursor.GetString(cursor.GetColumnIndex(projection[2]))
  105. });
  106. } while (cursor.MoveToNext());
  107. }
  108. }
  109. }
  110.  
  111. public class ch1903Contact
  112. {
  113. public long Id { get; set; }
  114. public string DisplayName { get; set; }
  115. public string PhotoId { get; set; }
  116. }
  117. }

【Android】19.3 ContentProvider及安卓进一步封装后的相关类的更多相关文章

  1. Android开发技巧——ViewPager加View情况封装PagerAdapter的实现类

    ViewPager是Android的support库中的一个控件. ViewPager + Fragment的使用,已经有FragmentAdapter的实现可以帮助我们快速进行开发了: ViewPa ...

  2. Android开发之Toast吐司的一个封装好的工具类。带有源代码java文件,

    import android.content.Context; import android.widget.Toast; //Toast统一管理类 public class T { private T ...

  3. Android MVP开发模式及Retrofit + RxJava封装

    代码已上传到Github,因为接口都是模拟无法进行测试,明白大概的逻辑就行了! 欢迎浏览我的博客--https://pushy.site 1. MVP模式 1.1 介绍 如果熟悉MVP模式架构的话,对 ...

  4. 【转】android四大组件--ContentProvider详解

    一.相关ContentProvider概念解析: 1.ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences. ...

  5. Android四大组件--ContentProvider详解(转)

    一.相关ContentProvider概念解析: 1.ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences. ...

  6. Android RecyclerView单击、长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类

     Android RecyclerView单击.长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类 我写的附录文章2,介绍了 ...

  7. Unity开发Android应用程序:调用安卓应用程序功能

    开发环境: Eclipse3.4 + adt12 + jdk6 + AndroidSDK2.2 Unity3.4 + windows7 测试设备: HTC Desire HD 本文要涉及到的几个重点问 ...

  8. Android开发之ContentProvider的简单使用

    ContentProvider,内容提供者 官网结构图: 作为四大组件之一的ContentProvider,主要是用于应用间数据共享使用的. ContentProvider把应用的数据封装起来,然后提 ...

  9. DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)

    DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类) 一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据 ...

随机推荐

  1. 【.NET中AOP的实现方案】静态代理

    Spring AOP 应该是比较出名的了,今天说的是C#里的AOP,C#的AOP实现的方式有很多种,现在就先介绍静态代理的实现方案: 模拟场景:我们在删除用户,或者更新用户的时候进行数据原始备份,这样 ...

  2. 有间距的表格布局 table布局

    1.先看有间距的布局效果: 2.少说多做,直接看代码(代码中有注释) <!DOCTYPE html> <html lang="zh"> <head&g ...

  3. Python之L.pop()和del L[i]

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #Python之L.pop()和del L[i] #http://python.jobbole.com/826 ...

  4. 如何查询端口号和网址的ip地址?

    import socket print socket.gethostname()#主机名 hostname=socket.gethostname() #传递主机名 print socket.getho ...

  5. doGet和doPost区别

    1,form运行方式 当form框里面的method为get时,执行doGet方法当form框里面的method为post时,执行doPost方法 2,生成方式 get方式有四种:1)直接在URL地址 ...

  6. jQuery正则:电话、身份证、邮箱简单校验

    if (!(/^1[3,5,6,7,8,9]\d{9}$/).test(e.detail.value.data_phone)) { wx.showToast({ title: '请输入有效11位手机号 ...

  7. JavaScript-实现滚动条

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. 路径,通过navigation可以查看 *.class文件

    ?.class文件内的代码所在的文件的路径默认 举例1:读取项目根目录下的数据. private static void readRoot() throws FileNotFoundException ...

  9. HDUOJ-----(1072)Nightmare(bfs)

    Nightmare Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  10. JavaScript 设计模式之单例模式

    一.单例模式概念解读 1.单例模式概念文字解读 单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象.在Ja ...