橘子味的心
标题:7.6 使用系统提供的ContentProvider

Android 系统提供了很多 ContentProvider,以便在应用程序间共享系统数据。

系统提供的 ContentProvider 都存放在 android.provider 包下,例如 android.provider.ContactsContract、android.provider.MediaStore、android.provider.CalendarContract 等。

本节以访问系统联系人列表为例,讲解如何通过系统提供的 ContentProvider 获取数据。

在 Android 2.0(API Level 5)之前,系统所提供的联系人 ContentProvider 为 android.provider.Contacts。

从 Android 2.0 开始,联系人列表相关信息被存放在 android.provider.ContactsContract 中。使用 ContactsContract 获取系统联系人列表的方法与之前有所不同,虽然形式上较以前复杂了一点,但是可以获取一个联系人的多个电话号码。

实例 ContactsCPDemo 演示了使用 ContactsContract 获取系统中所有联系人的名字和电话号码,并且显示出来的过程。为方便起见,假定每个联系人仅有一个电话号码,其运行效果如图 1 所示。

ContactsCPDemo界面
图 1  ContactsCPDemo界面

该效果由 ListView 组件实现。实例 ContactsCPDemo 中布局文件 main.xml 的代码如下:
  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. android:orientation="vertical">
  6.  
  7. <TextView
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:text="联系人列表如下:" />
  11.  
  12. <ListView
  13. android:id="@+id/listView"
  14. android:layout_width="fill_parent"
  15. android:layout_height="wrap_content"
  16. android:padding="5dip" />
  17. </LinearLayout>
实例 ContactsCPDemo 要访问系统联系人列表,需要拥有“android.permission.READ_CONTACTS”权限。

实例 ContactsCPDemo 中 AndroidManifest.xml 文件的代码如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="introduction.android.contactscpdemo">
  4.  
  5. <uses-permission android:name="android.permission.READ_CONTACTS" />
  6. <application
  7. android:allowBackup="true"
  8. android:icon="@mipmap/ic_launcher"
  9. android:label="@string/app_name"
  10. android:roundIcon="@mipmap/ic_launcher_round"
  11. android:supportsRtl="true"
  12. android:theme="@style/AppTheme">
  13. <activity android:name=".MainActivity">
  14. <intent-filter>
  15. <action android:name="android.intent.action.MAIN" />
  16. <category android:name="android.intent.category.LAUNCHER" />
  17. </intent-filter>
  18. </activity>
  19. </application>
  20.  
  21. </manifest>
实例 ContactsCPDemo 中 MainActivity.java 文件的代码如下:
  1. package introduction.android.contactscpdemo;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.Map;
  6.  
  7. import android.app.Activity;
  8. import android.database.Cursor;
  9. import android.os.Bundle;
  10. import android.provider.ContactsContract;
  11. import android.widget.ListView;
  12. import android.widget.SimpleAdapter;
  13.  
  14. public class MainActivity extends Activity {
  15. private SimpleAdapter listAdapter;
  16. private ListView listview;
  17.  
  18. private ArrayList<Map<String, String>> data;
  19. private HashMap<String, String> item;
  20.  
  21. /**
  22. * Called when the activity is first created.
  23. */
  24.  
  25. @Override
  26. public void onCreate(Bundle savedInstanceState) {
  27. super.onCreate(savedInstanceState);
  28. setContentView(R.layout.activity_main);
  29. listview = (ListView) this.findViewById(R.id.listView);
  30. data = new ArrayList<Map<String, String>>();
  31. Cursor cursor = this.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
  32. while (cursor.moveToNext()) {
  33. int idFieldIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID);
  34. int id = cursor.getInt(idFieldIndex);//根据列名取得该联系人的id
  35. int nameFieldIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
  36. String name = cursor.getString(nameFieldIndex);
  37. //根据列名取得该联系人的name
  38. int numCountFieldIndex = cursor.getColumnIndex
  39. (ContactsContract.Contacts.HAS_PHONE_NUMBER);
  40. //获取联系人的电话号码个数
  41. int numCount = cursor.getInt(numCountFieldIndex);
  42. String phoneNumber = "";
  43. if (numCount > 0) { //联系人至少有一个电话号码
  44. //在类 ContactsContract.CommonDataKinds.Phone中根据id查询相应联系人的所有电话
  45. Cursor phonecursor = getContentResolver().query(
  46. ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?", new String[]{Integer.toString(id)}, null);
  47. if (phonecursor.moveToFirst()) {
  48. //仅读取第一个电话号码
  49. int numFieldIndex = phonecursor.getColumnIndex(ContactsContract.
  50. CommonDataKinds.Phone.NUMBER);
  51. phoneNumber = phonecursor.getString(numFieldIndex);
  52. }
  53. }
  54. item = new HashMap<String, String>();
  55. item.put("name", name);
  56. item.put("phoneNumber", phoneNumber);
  57. data.add(item);
  58. }
  59. listAdapter = new SimpleAdapter(this, data,
  60. android.R.layout.simple_list_item_2, new String[]{
  61. "name", "phoneNumber"
  62. },
  63. new int[]{android.R.id.text1, android.R.id.text2});
  64. listview.setAdapter(listAdapter);
  65.  
  66. }
  67. }
其中:
  1. listAdapter = new SimpleAdapter(this, data,
  2. android.R.layout.simple_list_item_2, new String[]{
  3. "name", "phoneNumber"
  4. },
  5. new int[]{android.R.id.text1, android.R.id.text2});
  6. listview.setAdapter(listAdapter);
使用了 Android 系统提供的 simple_list_item_2 布局,并将该布局应用到 main.xml 文件的 ListView 组件中。