【摘】ContentProvider总结
ContentProvider一般译作内容提供者,官方文档中的解释:它用来管理结构化数据的访问。通过它我们可以共享自己应用中的数据,或者访问别的应用提供的数据,比如‘联系人’应用就实现了ContentProvider,通过它提供的ContentProvider我们可以查询、删除、更新联系人数据。
ContentProvider简介
ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以URI的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentResolver根据URI去访问\操作指定的数据。ContentProvider可以看作是一个网站,用来提供各种数据;ContentResolver则可当成浏览器。我们访问某个网站其实就是想获取那个网站上的数据。而且我们是通过浏览器与网站交互的。
开发步骤
1.从ContentProvider派生出一个子类,并重写如下方法:
public boolean onCreate() 该方法在ContentProvider创建后就会被调用, Android在系统启动时就会创建ContentProvider 。
public Uri insert(Uri uri, ContentValues values) 该方法用于供外部应用往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs) 该方法用于供外部应用从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 该方法用于供外部应用更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 该方法用于供外部应用从ContentProvider中获取数据。
public String getType(Uri uri) 该方法用于返回当前Url所代表数据的MIME类型。
如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,例如:要得到person记录的Uri为content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于单一数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。
2.在AndroidManifest.xml中注册之,和其它组件的注册过程类似。
<!-- 注册一个ContentProvider --> <provider android:name=".ExampleProvider" android:authorities="com.example.provider"/>
其中authorities属性就相当于网站的url。
使用ContentResolver操作ContentProvider中的数据
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
public Uri insert(Uri uri, ContentValues values) 该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs) 该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 该方法用于从ContentProvider中获取数据。
这些方法的第一个参数为Uri,代表要操作的是哪个ContentProvider和对其中的什么数据进行操作,假设给定的是: Uri.parse(“content://cn.itcast.provider.personprovider/person/10”),那么将会对主机名为cn.itcast.provider.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。
URI介绍:
Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件等他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
UriMatcher类使用介绍
因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。 UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
/常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码 UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH); //如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1 sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码 //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2 sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符 switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) { case 1 break; case 2 break; default://不匹配 break; }
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
ContentUris类使用介绍
ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
Uri resultUri = ContentUris.withAppendedId(uri, 10); //生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
parseId(uri)方法用于从路径中获取ID部分: Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10
示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package org.crazyit.content; 2 3 import java.util.ArrayList; 4 5 import android.app.Activity; 6 import android.app.AlertDialog; 7 import android.content.ContentUris; 8 import android.content.ContentValues; 9 import android.database.Cursor; 10 import android.net.Uri; 11 import android.os.Bundle; 12 import android.provider.ContactsContract; 13 import android.provider.ContactsContract.CommonDataKinds.Email; 14 import android.provider.ContactsContract.CommonDataKinds.Phone; 15 import android.provider.ContactsContract.CommonDataKinds.StructuredName; 16 import android.provider.ContactsContract.RawContacts; 17 import android.provider.ContactsContract.RawContacts.Data; 18 import android.view.Gravity; 19 import android.view.View; 20 import android.view.View.OnClickListener; 21 import android.view.ViewGroup; 22 import android.widget.AbsListView; 23 import android.widget.BaseExpandableListAdapter; 24 import android.widget.Button; 25 import android.widget.EditText; 26 import android.widget.ExpandableListAdapter; 27 import android.widget.ExpandableListView; 28 import android.widget.TextView; 29 import android.widget.Toast; 30 31 public class ContactProviderTest extends Activity { 32 Button search; 33 Button add; 34 35 @Override 36 public void onCreate(Bundle savedInstanceState) { 37 super.onCreate(savedInstanceState); 38 setContentView(R.layout.main); 39 // 获取系统界面中查找、添加两个按钮 40 search = (Button) findViewById(R.id.search); 41 add = (Button) findViewById(R.id.add); 42 search.setOnClickListener(new OnClickListener() { 43 @Override 44 public void onClick(View source) { 45 // 定义两个List来封装系统的联系人信息、指定联系人的电话号码、Email等详情 46 final ArrayList<String> names = new ArrayList<String>(); 47 final ArrayList<ArrayList<String>> details = new ArrayList<ArrayList<String>>(); 48 // 使用ContentResolver查找联系人数据 49 Cursor cursor = getContentResolver().query( 50 ContactsContract.Contacts.CONTENT_URI, null, null, 51 null, null); 52 // 遍历查询结果,获取系统中所有联系人 53 while (cursor.moveToNext()) { 54 // 获取联系人ID 55 String contactId = cursor.getString(cursor 56 .getColumnIndex(ContactsContract.Contacts._ID)); 57 // 获取联系人的名字 58 String name = cursor.getString(cursor 59 .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); 60 names.add(name); 61 // 使用ContentResolver查找联系人的电话号码 62 Cursor phones = getContentResolver().query( 63 ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 64 null, 65 ContactsContract.CommonDataKinds.Phone.CONTACT_ID 66 + " = ?", new String[] { contactId }, null); 67 ArrayList<String> detail = new ArrayList<String>(); 68 // 遍历查询结果,获取该联系人的多个电话号码 69 while (phones.moveToNext()) { 70 // 获取查询结果中电话号码列中数据。 71 String phoneNumber = phones.getString(phones 72 .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); 73 detail.add("电话号码:" + phoneNumber); 74 } 75 phones.close(); 76 // 使用ContentResolver查找联系人的Email地址 77 Cursor emails = getContentResolver().query( 78 ContactsContract.CommonDataKinds.Email.CONTENT_URI, 79 null, 80 ContactsContract.CommonDataKinds.Email.CONTACT_ID 81 + " = " + contactId, null, null); 82 // 遍历查询结果,获取该联系人的多个Email地址 83 while (emails.moveToNext()) { 84 // 获取查询结果中Email地址列中数据。 85 String emailAddress = emails.getString(emails 86 .getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); 87 detail.add("邮件地址:" + emailAddress); 88 } 89 emails.close(); 90 details.add(detail); 91 } 92 cursor.close(); 93 // 加载result.xml界面布局代表的视图 94 View resultDialog = getLayoutInflater().inflate( 95 R.layout.result, null); 96 // 获取resultDialog中ID为list的ExpandableListView 97 ExpandableListView list = (ExpandableListView) resultDialog 98 .findViewById(R.id.list); 99 // 创建一个ExpandableListAdapter对象 100 ExpandableListAdapter adapter = new BaseExpandableListAdapter() { 101 // 获取指定组位置、指定子列表项处的子列表项数据 102 @Override 103 public Object getChild(int groupPosition, int childPosition) { 104 return details.get(groupPosition).get(childPosition); 105 } 106 107 @Override 108 public long getChildId(int groupPosition, int childPosition) { 109 return childPosition; 110 } 111 112 @Override 113 public int getChildrenCount(int groupPosition) { 114 return details.get(groupPosition).size(); 115 } 116 117 private TextView getTextView() { 118 AbsListView.LayoutParams lp = new AbsListView.LayoutParams( 119 ViewGroup.LayoutParams.FILL_PARENT, 64); 120 TextView textView = new TextView( 121 ContactProviderTest.this); 122 textView.setLayoutParams(lp); 123 textView.setGravity(Gravity.CENTER_VERTICAL 124 | Gravity.LEFT); 125 textView.setPadding(36, 0, 0, 0); 126 textView.setTextSize(20); 127 return textView; 128 } 129 130 // 该方法决定每个子选项的外观 131 @Override 132 public View getChildView(int groupPosition, 133 int childPosition, boolean isLastChild, 134 View convertView, ViewGroup parent) { 135 TextView textView = getTextView(); 136 textView.setText(getChild(groupPosition, childPosition) 137 .toString()); 138 return textView; 139 } 140 141 // 获取指定组位置处的组数据 142 @Override 143 public Object getGroup(int groupPosition) { 144 return names.get(groupPosition); 145 } 146 147 @Override 148 public int getGroupCount() { 149 return names.size(); 150 } 151 152 @Override 153 public long getGroupId(int groupPosition) { 154 return groupPosition; 155 } 156 157 // 该方法决定每个组选项的外观 158 @Override 159 public View getGroupView(int groupPosition, 160 boolean isExpanded, View convertView, 161 ViewGroup parent) { 162 TextView textView = getTextView(); 163 textView.setText(getGroup(groupPosition).toString()); 164 return textView; 165 } 166 167 @Override 168 public boolean isChildSelectable(int groupPosition, 169 int childPosition) { 170 return true; 171 } 172 173 @Override 174 public boolean hasStableIds() { 175 return true; 176 } 177 }; 178 // 为ExpandableListView设置Adapter对象 179 list.setAdapter(adapter); 180 // 使用对话框来显示查询结果。 181 new AlertDialog.Builder(ContactProviderTest.this) 182 .setView(resultDialog).setPositiveButton("确定", null) 183 .show(); 184 } 185 }); 186 // 为add按钮的单击事件绑定监听器 187 add.setOnClickListener(new OnClickListener() { 188 @Override 189 public void onClick(View v) { 190 // 获取程序界面中的3个文本框 191 String name = ((EditText) findViewById(R.id.name)).getText() 192 .toString(); 193 String phone = ((EditText) findViewById(R.id.phone)).getText() 194 .toString(); 195 String email = ((EditText) findViewById(R.id.email)).getText() 196 .toString(); 197 // 创建一个空的ContentValues 198 ContentValues values = new ContentValues(); 199 // 向RawContacts.CONTENT_URI执行一个空值插入, 200 // 目的是获取系统返回的rawContactId 201 Uri rawContactUri = getContentResolver().insert( 202 RawContacts.CONTENT_URI, values); 203 long rawContactId = ContentUris.parseId(rawContactUri); 204 205 values.clear(); 206 values.put(Data.RAW_CONTACT_ID, rawContactId); 207 // 设置内容类型 208 values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 209 // 设置联系人名字 210 values.put(StructuredName.GIVEN_NAME, name); 211 // 向联系人URI添加联系人名字 212 getContentResolver().insert( 213 android.provider.ContactsContract.Data.CONTENT_URI, 214 values); 215 216 values.clear(); 217 values.put(Data.RAW_CONTACT_ID, rawContactId); 218 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 219 // 设置联系人的电话号码 220 values.put(Phone.NUMBER, phone); 221 // 设置电话类型 222 values.put(Phone.TYPE, Phone.TYPE_MOBILE); 223 // 向联系人电话号码URI添加电话号码 224 getContentResolver().insert( 225 android.provider.ContactsContract.Data.CONTENT_URI, 226 values); 227 228 values.clear(); 229 values.put(Data.RAW_CONTACT_ID, rawContactId); 230 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 231 // 设置联系人的Email地址 232 values.put(Email.DATA, email); 233 // 设置该电子邮件的类型 234 values.put(Email.TYPE, Email.TYPE_WORK); 235 // 向联系人Email URI添加Email数据 236 getContentResolver().insert( 237 android.provider.ContactsContract.Data.CONTENT_URI, 238 values); 239 240 Toast.makeText(ContactProviderTest.this, "联系人数据添加成功", 8000) 241 .show(); 242 } 243 }); 244 } 245 }
PS:最近几天,基本上把官方文档中关于ContentProvider的部分看完了。可懒得自己写总结了,以上内容基本上全部来自黎活明的android培训课件。