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

时间:2023-02-26 11:44:55

分类: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、运行截图

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

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

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文件夹下添加该文件。

<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/ch1903_ContactImage"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="5dp" />
<TextView
android:id="@+id/ch1903_ContactName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_marginLeft="5dp" />
</LinearLayout>

(4)添加ch1903Main.axml

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@+id/ch1903_ContactsListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>

(5)添加ch1903MainActivity.cs

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Provider;
using Android.Database; namespace MyDemos.SrcDemos
{
[IntentFilter(new[] { Intent.ActionMain }, Categories = new[] { ch.MyDemosCategory })]
[Activity(Label = "【例19-3】ContentProvider基本用法")]
public class ch1903MainActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ch1903Main);
var contactsAdapter = new ContactsAdapter(this);
var contactsListView = FindViewById<ListView>(Resource.Id.ch1903_ContactsListView);
contactsListView.Adapter = contactsAdapter;
}
} public class ContactsAdapter : BaseAdapter<ch1903Contact>
{
List<ch1903Contact> contactList;
Activity activity; public override int Count
{
get { return contactList.Count; }
} public override ch1903Contact this[int position]
{
get { return contactList[position]; }
} public ContactsAdapter(Activity activity)
{
this.activity = activity;
FillContacts();
} public override long GetItemId(int position)
{
return contactList[position].Id;
} public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = convertView ?? activity.LayoutInflater.Inflate(Resource.Layout.ch1903ContactListItem, parent, false);
var contactName = view.FindViewById<TextView>(Resource.Id.ch1903_ContactName);
var contactImage = view.FindViewById<ImageView>(Resource.Id.ch1903_ContactImage);
contactName.Text = contactList[position].DisplayName;
if (contactList[position].PhotoId == null)
{
contactImage = view.FindViewById<ImageView>(Resource.Id.ch1903_ContactImage);
contactImage.SetImageResource(Resource.Drawable.ch1903_contact_picture);
}
else
{
var contactUri = ContentUris.WithAppendedId(ContactsContract.Contacts.ContentUri, contactList[position].Id);
var contactPhotoUri = Android.Net.Uri.WithAppendedPath(contactUri, ContactsContract.Contacts.Photo.ContentDirectory);
contactImage.SetImageURI(contactPhotoUri);
}
return view;
} private void FillContacts()
{
var uri = ContactsContract.Contacts.ContentUri;
string[] projection = {
ContactsContract.Contacts.InterfaceConsts.Id,
ContactsContract.Contacts.InterfaceConsts.DisplayName,
ContactsContract.Contacts.InterfaceConsts.PhotoId
}; // 下面这条语句已过时,不要使用它
//var cursor = activity.ManagedQuery (uri, projection, null, null, null); // 如果用下面这条语句,不用时必须调用cursor.Close()关闭它
//var cursor = activity.ContentResolver.Query(uri, projection, null, null, null); // 下面是建议的用法
var loader = new CursorLoader(activity, uri, projection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();
contactList = new List<ch1903Contact>();
if (cursor.MoveToFirst())
{
do
{
contactList.Add(new ch1903Contact
{
Id = cursor.GetLong(cursor.GetColumnIndex(projection[0])),
DisplayName = cursor.GetString(cursor.GetColumnIndex(projection[1])),
PhotoId = cursor.GetString(cursor.GetColumnIndex(projection[2]))
});
} while (cursor.MoveToNext());
}
}
} public class ch1903Contact
{
public long Id { get; set; }
public string DisplayName { get; set; }
public string PhotoId { get; set; }
}
}

【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 &plus; RxJava封装

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

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

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

  5. Android四大组件--ContentProvider详解&lpar;转&rpar;

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

  6. Android RecyclerView单击、长按事件&colon;基于OnItemTouchListener &plus;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. 基于Hexo和Github搭建博客

    搭建自己的个人博客. 准备工作 确保电脑需要已下载安装node和npm.查看安装是否成功,windows只需在命令行输入以下两条命令即可. 1 2 $ node -v $ npm -v 安装hexo ...

  2. ASP&period;NET使用ConfigurationSection在Web&period;Config创建自定义配置节

    主要代码,一定要继续System.Configuration.ConfigurationSection,具体的节点名称可以自行修改 using System; using System.Data; u ...

  3. Linux主机通过代理服务器进行网络连接

    公司的不允许访问外网,但是访问外网需要配置代理,window配置均好配置,在Linux的命令行底下,一般的程序都是使用http_proxy和ftp_proxy这两个环境变量来获得代理设置的.1.在/e ...

  4. c&plus;&plus;&lpar;堆排序&rpar;

    堆排序是另外一种常用的递归排序.因为堆排序有着优秀的排序性能,所以在软件设计中也经常使用.堆排序有着属于自己的特殊性质,和二叉平衡树基本是一致的.打一个比方说,处于大堆中的每一个数据都必须满足这样一个 ...

  5. 通过 txt 文件批量导入需要批量处理的数据的标识字段

    前言 在一些工作中,可能需要对数据库中的一些数据(批量)进行处理(修改或者查询),而数据的来源是你的同事,换句话说就是这批数据不可能通过某些查询条件查出来, 而这批数据又比较多,比如几百.几千甚至几万 ...

  6. &commat;JSONField使用

    参考博客:http://www.cnblogs.com/yucy/p/9057049.html 1.经常遇到这种情况,传过来json的key名和我们javaBean的属性名不一样,导致接收不到: Ch ...

  7. Ext 日期格式化

    //日期格式化 Date.prototype.Format = function (fmt) { var o = { , //月份 "d+": this.getDate(), // ...

  8. 【Zookeeper系列】zookeeper面试题(转)

    原文链接:https://segmentfault.com/a/1190000014479433 1.ZooKeeper是什么? ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是 ...

  9. 1&period; 怎么设置可以使得虚拟机里面既可以访问主机也可以访问局域网而且是静态ip

    方法1: Bridged方式(桥接): (1). 虚拟机网络适配器设置为桥接 (2). 主机设置静态ip (3). 虚拟机也设置静态ip且和宿主机在同一网段 Bridged方式: 在图1中Networ ...

  10. 【CodeForces】576 C&period; Points on Plane

    [题目]C. Points on Plane [题意]给定坐标系中n个点的坐标(范围[0,10^6]),求一种 [ 连边形成链后总长度<=2.5*10^9 ] 的方案.n<=10^6. [ ...