在这里,我们将给大家分享关于android–不共享的应用程序是否需要ContentProvider?的知识,让您更了解不共享app的本质,同时也会涉及到如何更有效地AndroidContacts(an
在这里,我们将给大家分享关于android – 不共享的应用程序是否需要Content Provider?的知识,让您更了解不共享app的本质,同时也会涉及到如何更有效地Android Contacts (android通讯录读取)-content provider、Android Content Provider (内容提供者)、Android Content Provider 总结思维导图、android Content Provider 详解的内容。
本文目录一览:- android – 不共享的应用程序是否需要Content Provider?(不共享app)
- Android Contacts (android通讯录读取)-content provider
- Android Content Provider (内容提供者)
- Android Content Provider 总结思维导图
- android Content Provider 详解
android – 不共享的应用程序是否需要Content Provider?(不共享app)
现在我的问题是,我真的需要内容提供商吗?甚至官方指南也说:
You don’t need to develop your own provider if you don’t intend to share your data with other applications. However,you do need your own provider to provide custom search suggestions in your own application. You also need your own provider if you want to copy and paste complex data or files from your application to other applications.
而且我认为我不需要任何关于它的因此它会产生不必要的复杂性.
那么..我应该怎么做,破解我自己的CursorLoader只能使用我的数据库这样的(CursorLoader usage without ContentProvider),老实说,我真的不喜欢,或者我应该把它搞砸并顺从制作提供商?
谢谢!
解决方法
SQLiteCursorLoader
)来直接查询sqliteDatabase.文档是正确的,因为如果您的应用程序只需要对本地数据的简单访问(而不是与不同的进程/应用程序共享该数据),您实际上并不需要ContentProvider.
也就是说,ContentProvider确实提供了一些好处.例如,您需要使用SearchManager实现SyncAdapter或搜索界面.我尝试将这些结合到我的应用程序中,所以我发现自己一直在实现ContentProviders. ContentResolver还提供了一种在进行更改时向底层数据源提供全局通知的简便方法.例如,CursorLoader将在其Cursor上注册ContentObserver,当您在给定的Uri上调用ContentResolver#notifyChange(Uri uri,ContentObserver observer)时,会导致Cursor接收通知.如果您要直接从sqliteDatabase加载数据,那么设置它需要更多的工作.
Android Contacts (android通讯录读取)-content provider
Android Contacts (android通讯录读取)-content provider
Content Provider
在数据处理中,Android通常使用Content Provider的方式。Content Provider使用Uri实例作为句柄的数据封装的,很方便地访问地进行数据的增、删、改、查的操作。Android并不提供所有应用共享的数据存储,采用content Provider,提供简单便捷的接口来保持和获取数据,也可以实现跨应用的数据访问。简单地说,Android通过content Provider从数据的封装中获取信息。
Content provider使用Uri的方式来定位信息。以“content://” 开头来表明这是一个content URI。例如“content://contstans/5”,其中“content://constans”称为base URI,相当于数据的namespace,它的结构可以更为复杂,可以有多层结构。例子中的“5”,则是具体实例的标识。
一般来讲,Android的数据存储有4种方式:
1、 Preferences,参见Preference的使用,通常都是键值对(name-value pair)。
2、文件:在手机设备或者外设上存储,缺省的只能由创建的应用访问。
3、数据库(RDBMS):SQLite方式,参见SQLite的使用,由创建的应用访问。
4、网络:Android提供API远程在服务器上存储数据。
如果我们需要在应用中共享,采用Content Provider。无论数据具体的存储方式,Content Provider提供了一个统一的接口。数据将采用类表格的方式提供,有行有列,列表示不同属性的数据,例如电话号码、电邮地址等。每个记录(每行)都有一个唯一的_ID字段来标识。在以后具体的代码中看更直观看出。
原生providers
Android提供一些原生的content provider,来往问系统中的视频、图像和联系人信息等等。例如联系人的URI为“content://com.android.contacts /contacts”,原生的providers一般都有定义,例如联系人为 ContactsContract.Contacts.CONTENT_URI。由于系统不同版本可能会存在差异,我们应尽可能使用系统的定义。
在android.provider的包中,可以查看原生的provider,例如有AlarmClock、Browser、CalendarContract、CallLog、 ContactsContract(包括有Contacts,Groups,PhoneLookup等)、MediaStore(Audio 『Albums、Artists、Genres、Playlists』、Files、Images、Video)和Setting。
通过Content Providers读取信息
我们利用原生provider联系人来看看如何来读取信息,联系人的数据结构比较复杂,后面会详细介绍,这里我们将尽可能简化,先对Content Provider有个直观的认识。核心是通过managedQuery( )来获取Cursor。Cursor实际返回是一个二维的表格,有行有列,行是具体的元素,列是该元素具体的属性。整个方式和SQLite非常相似。
//可以很方便将Cursor的内容映射到ListActivity上,具体参见Android学习笔记(四十二):SQLite,ListView,ContextMenu
public class Chapter26Test1 extendsListActivity {
private String[] INFO = new String[]{
ContactsContract.Contacts._ID, //对于Content Provider返回数据表格而言,注意唯一标识_ID通常是必须读取的,否则很容易报错
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Cursor contactCursor = managedQuery(ContactsContract.Contacts.CONTENT_URI,INFO, null,null,null);
ListAdapter adapter = new SimpleCursorAdapter(this,
R.layout.chapter_22_test1,contactCursor,
new String[]{ContactsContract.Contacts.DISPLAY_NAME,ContactsContract.Contacts.HAS_PHONE_NUMBER},
new int[]{R.id.c22_name,R.id.c22_gravity});
setListAdapter(adapter); //偷偷懒,本例子直接利用了Android学习笔记(四十二)中SQLite例子中的xml
}
}
说说Android联系人信息的组织结构及读取
这是Android给出的联系人组织结构图。分为三层。
第一层,Contact,即ContactContract.Contacts,是整合的联系人信息。
第二层,RawConact,即 ContactContract.RawContact,记录的是该联系人来自某信息源的信息,例如本地输入的,来自Google的,从微软 Exchange中导出的,或则来自某个社交网站的信息。每个RawContact记录的信息都来自同一信息源。
第三层,Data,即 ContactContract.Data,是具体的信息存储,例如记录联系人姓名,email信息,家庭电话,手机电话信息等等,每一个Data都存放一个具体的信息。在Data中的MIME TYPE说明存储信息的类型。具体在ContactContract.CommonDataKinds中定义。每个Data中有DATA1-DATA15 个字段来存储信息,各字段所代表的含义,也可以在CommonDataKinds中具体查到。
下面,我们一层一层地读取联系人信息,将更清晰地看到这个结构。要读取详细信息,对于Content Privider,关键是Uri逐层定位,才能获取信息。为了清晰表述,我们将整个路径写出来。
第一层信息,将返回联系人列表中的多个Contacts,Uri为ContactsContract.Contacts.CONTENT_URI
private String[] INFO_1= new String[]{
ContactsContract.Contacts._ID,//这是每个row,也就是每个联系人的唯一的ID标识
ContactsContract.Contacts.DISPLAY_NAME,
};
Cursor cursor = managedQuery(ContactsContract.Contacts.CONTENT_URI,INFO_1,null,null,null);
cursor是表格形式,每一个行表示一个联系人。要 读取哪些列,在第二个参数String[]中定义。可以选取那些列,在Android Reference中的ContactsContract.Contacts中的Column中可以查到。最关键的列信息为_ID,它是行,也就是每个联系人的唯一标识。除此之外,每个联系人的信息会根据旗下的RawContact进行整合,因此,我们可以查到联系的名字 ContactsContract.Contacts.DISPLAY_NAME等。
利用Contacts._ID,我们可以检索第二层的信息。
第二层信息,将返回某联系人的多个RawContacts
同样,返回表格中的列,可以查看 ContactsContract.RawContacts中查看。我们选取下面的信息,此外,如果要查看信息的来源,例如来自com.google,可通过RawContacts.ACCOUNT_TYPE和RawContacts.ACCOUNT_NAME两个列查看。
private String[ ] INFO_2 = {
ContactsContract.RawContacts._ID, //这是RawContact的唯一标识
ContactsContract.RawContacts.CONTACT_ID, //这是该RawContact关联的Contact._ID
};
通过查询全部的RawContacts,通过条件检索,要求联系人的ID为指定的某联系人。在下面的例子在managedQuery中给出了param3和param4的条件,注意参数3,如果我们有多个条件,可以用AND等逻辑符合进行表述。
Cursor cursor = managedQuery(ContactsContract.RawContacts.CONTENT_URI ,
INFO_2 ,
RawContacts.CONTACT_ID + "=?" ,
new String[]{String.valueOf(contactId)} ,
null);
通过RawContacts._ID,我们可以往下检索RawContacts下面各Data的信息内容。
第三层信息:将返回某RawContact的各Data的信息
可查询各列的信息见ContactsContract.Data的介绍。
private String INFO_3[] = {
ContactsContract.Data._ID, //这是Data信息块的唯一标识
ContactsContract.Data.CONTACT_ID, //关联第一层信息的CONTACT_ID
ContactsContract.Data.RAW_CONTACT_ID, //关联第二层信息的RAW_IDCONTACT_ID
ContactsContract.Data.MIMETYPE, //具体含义可查ContactsContract.CommonDataKinds
ContactsContract.Data.DATA1, //通常读取DATA1就可以,在具体的ContactsContract.CommonDataKinds.Phone/Email等查到DATA1-DATA15的含义
ContactsContract.Data.DATA2,
… …
ContactsContract.Data.DATA15,
};
读取的方式有两种。
方式一:指定定具体的Uri:
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawId);
Uri dataUri =Uri.withAppendedPath(rawContactUri,ContactsContract.RawContacts.Data.CONTENT_DIRECTORY);
Cursor cursor = managedQuery( dataUri, INFO_3,null, null, null);
方式二:另一种是利用RawContacts_ID或者Contact_ID,通过Data.CONTENT_URI,具体方式类RawContacts的检索。
Cursor cursor = managedQuery(ContactsContract.Data.CONTENT_URI ,
INFO_3 ,
ContactsContract.Data.RAW_CONTACT_ID + "=?" ,
new String[]{String.valueOf(rawId)} ,
null);
总结一下架构图。实际上Android的联系人提供了多种URI的的查询方式,具体参加Android的reference。

Android Content Provider (内容提供者)
什么是 Content Provider
- 应用程序间共享数据的一种方式
- 为存储和获取数据提供了统一的接口
- Android 为常见的一些数据提供了默认的 ContentProvider
- Uri : 通用资源标识符
创建和使用 Content Provider 的步骤:
图片从视频网上 copy 的
下面写一个利用 Content Provider 读取手机通讯录联系人姓名,并将名字显示在 TextView 中
xml 代码
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Demo01">
<TextView
android:id="@+id/module_act_people_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</android.support.constraint.ConstraintLayout>
Java 代码,里面该有的都注释了
public class Demo01 extends AppCompatActivity {
private TextView people_tv;
//希望获得姓名(通讯录内的姓名)
private String columns = ContactsContract.Contacts.DISPLAY_NAME;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo01);
people_tv = findViewById(R.id.module_act_people_tv);
//将联系人信息显示出来
people_tv.setText(getQueryData());
//添加访问系统通讯录权限
//<uses-permission android:name="android.permission.READ_CONTACTS" />
}
private CharSequence getQueryData(){
//用于保存获取的联系人
StringBuilder stringBuilder = new StringBuilder();
ContentResolver resolver = getContentResolver();
//查询记录
Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null, null);
//获取姓名记录的索引值
int displayNameIndex = cursor.getColumnIndex(columns);
//迭代获取索引
for (cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()){
String displayName = cursor.getString(displayNameIndex);
stringBuilder.append(displayName+"\n");
}
//关闭cursor
cursor.close();
return stringBuilder.toString();
}
}
Android Content Provider 总结思维导图
根据 Google Android Doc 总结:
1.Content Prodiver 的基本概念
2. 增删改查
3. 创建 Content Provider
4. 在 Manifest.xml 中定义
5.Content URI 详解
原文出处:http://www.mcjiffy.cn/353.html
android Content Provider 详解
Android中的Contentprovider机制可支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据。
Android提供了一些主要数据类型的Contentprovider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的Contentprovider。可以获得这些Contentprovider,查询它们包含的数据,当然前提是已获得适当的读取权限。
如果想公开自己的数据,那么可有两种办法:
创建自己的 Content provider ,需要继承ContentProvider类; 如果你的数据和已存在的Content provider 数据结构一致,可以将数据写到已存在的 Content provider 中,当然前提是获取写该 Content provider 的权限。比如把OA中的成员通讯信息加入到系统的联系人 Contentprovider 中。Content provider 基础
所有Contentprovider都需要实现相同的接口用于查询Contentprovider并返回数据,也包括增加、修改和删除数据。
首先需要获得一个ContentResolver的实例,可通过Activity的成员方法getContentResovler()方法:
ContentResolver cr = getContentResolver();
ContentResolver实例带的方法可实现找到指定的Contentprovider并获取到Contentprovider的数据。
ContentResolver的查询过程开始,Android系统将确定查询所需的具体Contentprovider,确认它是否启动并运行它。android系统负责初始化所有的Contentprovider,不需要用户自己去创建。实际上,contentprovider的用户都不可能直接访问到contentprovider实例,只能通过ContentResolver在中间代理。
数据模型
Contentprovider展示数据类似一个单个数据库表。其中:
每行有个带唯一值的数字字段,名为_ID,可用于对表中指定记录的定位; Content provider 返回的数据结构,是类似JDBC的ResultSet,在android中,是Cursor对象。 URI
每个contentprovider定义一个唯一的公开的URI,用于指定到它的数据集。一个contentprovider可以包含多个数据集(可以看作多张表),这样,就需要有多个URI与每个数据集对应。这些URI要以这样的格式开头:
content://
表示这个uri指定一个contentprovider。
如果你想创建自己的contentprovider,最好把自定义的URI设置为类的常量,这样简化别人的调用,并且以后如果更新URI也很容易。android定义了CONTENT_URI常量用于URI,比如:
android.provider.Contacts.Phones.CONTENT_URI
android.provider.Contacts.Photos.CONTENT_URI
要注意的是上面例子中的Contacts,已经在android 2.0及以上版本不赞成使用。
查询 Content provider
要想使用一个contentprovider,需要以下信息:
定义这个 content provider 的URI 返回结果的字段名称 这些字段的数据类型
如果需要查询contentprovider数据集的特定记录(行),还需要知道该记录的ID的值。
构建查询
查询就是输入URI等参数,其中URI是必须的,其他是可选的,如果系统能找到URI对应的contentprovider将返回一个Cursor对象。
可以通过ContentResolver.query()或者Activity.managedQuery()方法。两者的方法参数完全一样,查询过程和返回值也是相同的。区别是,通过Activity.managedQuery()方法,不但获取到Cursor对象,而且能够管理Cursor对象的生命周期,比如当Activity暂停(pause)的时候,卸载该Cursor对象,当Activity restart的时候重新查询。另外,也可以对一个没有处于Activity管理的Cursor对象做成被Activity管理的,通过调用 Activity.startManaginCursor()方法。
类似这样:
Cursor cur = managedQuery(myPerson, null, null, null, null);
其中第一个参数myPerson是Uri类型实例。
如果需要查询的是指定行的记录,需要用_ID值,比如ID值为23,URI将是类似:
content://. . . ./23
android提供了方便的方法,让开发者不需要自己拼接上面这样的URI,比如类似:
Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
或者:
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
二者的区别是一个接收整数类型的ID值,一个接收字符串类型。
其他几个参数:
names,可以为null,表示取数据集的全部列,或者声明一个String数组,数组中存放列名称,比如: People._ID 。一般列名都在该 Content provider 中有常量对应; 针对返回结果的过滤器,格式类似于SQL中的WHERE子句,区别是不带WHERE关键字,如果返回null表示不过滤,比如 name=? ; 前面过滤器的参数,是String数组,是针对前面条件中?占位符的值; 排序参数,类似SQL的ORDER BY字句,不过不需要写ORDER BY部分,比如 name desc ,如果不排序,可输入null。
返回值是Cursor对象,游标位置在第一条记录之前。
下面实例适用于android 2.0及以上版本,从android通讯录中得到姓名字段:
Cursor cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.
CONTENT_URI, null, null,null,null);
返回值的内容
返回值的内容类似上图,不同的contentprovider会有不同的列和名称,但是会有两个相同的列,上面提到过的一个是_ID,用于唯一标识记录,还有一个_COUNT,用于记录整个结果集的大小,可以看到上面图中的_COUNT的值是相同的。
读取返回的数据
如果在查询的时候使用到ID,那么返回的数据只有一条记录。在其他情况下,一般会有多条记录。和JDBC的ResultSet类似,需要操作游标遍历结果集,在每行,再通过列名获取到列的值,可以通过getString()、getInt()、getFloat()等方法获取值。比如类似下面:
while (cursor.moveToNext()) {
builder.append(cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)))
.append("-");
}
和JDBC中不同,没有直接通过列名获取列值的方法,只能先列名获取到列的整型索引值,然后再通过该索引值定位获取列的值。
编辑数据
可以通过contentprovider实现以下编辑功能:
增加新的记录; 在已经存在的记录中增加新的值; 批量更新已经存在的多个记录; 删除记录。
所有的编辑功能都是通过ContentResolver的方法实现。一些Contentprovider对权限要求更严格一些,需要写的权限,如果没有会报错。
增加记录
要想增加记录到contentprovider,首先,要在ContentValues对象中设置类似map的键值对,在这里,键的值对应contentprovider中的列的名字,键值对的值,是对应列希望的类型。然后,调用ContentResolver.insert()方法,传入这个ContentValues对象,和对应Contentprovider的URI即可。返回值是这个新记录的URI对象。这样你可以通过这个URI获得包含这条记录的Cursor对象。比如:
ContentValues values = new ContentValues();
values.put(People.NAME, "Abraham Lincoln");
Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
在原有记录上增加值
如果记录已经存在,可在记录上增加新的值,或者编辑已经存在的值。
首先要过去到原来的值对象,然后要清除原有的值,然后像上面增加记录一样即可:
Uri uri=Uri.withAppendedPath(People.CONTENT_URI, "23");
Uri phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
values.clear();values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);values.put(People.Phones.NUMBER, "1233214567");getContentResolver().insert(phoneUri, values);
批量更新值
批量更新一组记录的值,比如NY改名为Eew York。可调用ContenResolver.update()方法。
删除记录
如果是删除单个记录,调用ContentResolver.delete()方法,URI参数,指定到具体行即可。
如果是删除多个记录,调用ContentResolver.delete()方法,URI参数指定Contentprovider即可,并带一个类似SQL的WHERE子句条件。这里和上面类似,不带WHERE关键字。
创建自己的 Content provider
创建contentprovider,需要:
设置存储系统。大多数 content provider 使用文件或者SQLite数据库,不过你可以用任何方式存储数据。android提供SQLiteoOpenHelper帮助开发者创建和管理SQLiteDatabase。 继承ContentProvider,提供对数据的访问。 在manifest文件中声明 content provider 。 继承ContentProvider类
必须定义ContentProvider类的子类,需要实现如下方法:
query()
insert()
update()
delete()
getType()
onCreate()
query()方法,返回值是Cursor实例,用于迭代请求的数据。Cursor是一个接口。android为该接口提供了一些只读的(和 JDBC的ResultSet不一样,后者还提供可写入的可选特性)Cursor实现。比如SQLiteCursor,可迭代SQLite数据库中的数据。可以通过SQLiteDatabase类的query()方法获取到该Cursor实例。还有其他的Cursor实现,比如 MatrixCursor,用于数据不是存储在数据库的情况下。
因为Contentprovider可能被多个ContentResolver对象在不同的进程和线程中调用,因此实现Contentprovider必须考虑线程安全问题。
作为良好的习惯,在实现编辑数据的代码中,要调用ContentResolver.notifyChange()方法,通知那些监听数据变化的监听器。
在实现子类的时候,还有一些步骤可以简化Contentprovider客户端的使用:
定义public static final Uri常量,名称为CONTENT_URI:
public static final UriCONTENT_URI =
Uri.parse("content://com.example.codelab.transportationprovider");
如果有多个表,它们也是使用相同的CONTENT_URI,只是它们的路径部分不同。
也就是说红色框部分是一致的。
定义返回的列名,public static final,列名的值,比如使用SQLite数据库作为存储,对应表的列名。
在文档中要写出各个列的数据类型,便于使用者读取。
如果需要处理新的MIME数据类型,比如通过Intent的方式,并且带data的mimeType(参见总结一下Intent概念),那么需要在ContentProvider.getType()方法中进行处理,参见编写完整的Contentprovider示例编写一个getType方法部分。
如果处理数据库表中超大的数据,比如很大的位图文件,一般存在文件系统中,可以参照在contentprovider中使用大型二进制文件,这样第三方的contentprovider使用者,可以访问不属于它权限的文件,通过contentprovider做代理。
声明 Content Provider
创建ContentProvider后,需要在manifest文件中声明,android系统才能知道它,当其他应用需要调用该ContentProvider时才能创建或者调用它。
语法类似:
<providerandroid:name="com.easymorse.cp.MyContentProvider"
android:authorities="com.easymorse.cp.mycp"></provider>
android:name要写ContentProvider继承类的全名。
android:authorities要写和CONTENT_URI常量的B部分(见上面图)。
注意不要把上图C和D部分加到authorities中去。authorities是用来识别ContentProvider的,C和D部分实际上是ContentProvider内部使用的。
本文参考:http://androidappdocs.appspot.com/guide/topics/providers/content-providers.html
关于android – 不共享的应用程序是否需要Content Provider?和不共享app的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Android Contacts (android通讯录读取)-content provider、Android Content Provider (内容提供者)、Android Content Provider 总结思维导图、android Content Provider 详解等相关知识的信息别忘了在本站进行查找喔。
本文标签: