Android联系人提供者探索器:深入解析与实践
立即解锁
发布时间: 2025-08-23 01:37:37 阅读量: 1 订阅数: 4 

### Android 联系人提供者探索器:深入解析与实践
#### 1. 联系人提供者与 ContactsContract API 概述
联系人提供者是一个复杂的数据库,而用于访问它的 ContactsContract API 则呈现出复杂的类和接口层次结构。要深入了解该 API,可参考其文档:[ContactsContract API 文档](http://developer.android.com/reference/android/provider/ContactsContract.html)。若对联系人提供者和 ContactsContract API 的区别仍有疑惑,可查看内容提供者设计与创建的相关文档:[内容提供者创建文档](http://developer.android.com/guide/topics/providers/content-provider-creating.html)。
ContactsContract API 的风格在 Android 中常见且惯用,但在一般 Java 实践中较为少见。它将 Java 类和接口与 REST 风格的 URI 对象系统相结合,用于访问提供者中的信息。这种独特的 API 风格有其优点和缺点:优点主要源于其在风格上对 REST 的模仿;缺点则在于可能会引发通过反射进行的探测,如果探测到 API 中未文档化的部分,可能会被指责未能对其实现进行抽象。
#### 2. 联系人提供者探索器应用介绍
示例应用通过枚举 API 中代表表的类以及每个表中的列,来探索联系人提供者中包含的数据。即查询 API 中命名的所有表的所有行,并显示每行中的所有列。可从 [GitHub 仓库](https://github.com/wileyenterpriseandroid/Examples.git) 和 [指定网站](www.wrox.com) 获取该应用的源代码。
要跟随学习,需将示例源代码导入到 Eclipse 工作区的项目中。运行该应用会呈现类似特定图示的显示效果。需注意,若数据库中没有联系人,则不会显示任何联系人信息。应用中的选项菜单可让你选择要查看的表,屏幕左侧的列表会显示表中的一列,你可根据该列的数据选择行。选择行后,行信息会显示在“Item”标签中,表信息会显示在“Table”标签中。
#### 3. 探索数据库的代码目标
示例程序的目标如下:
- 帮助你找到每个包含名为 `CONTENT_URI` 静态对象的类所对应的表,即通过 ContactsContract API 可访问的每个表。
- 让你了解表的结构,包括每个列的名称以及大型真实世界地址簿中的行数。
- 使你能够查看真实地址簿中的数据。
要查看地址簿中的内容,需编译并运行示例,确保看到与前文图示类似的界面。从选项菜单中选择不同的表,选择“Table”和“Data”标签以查看表信息和从屏幕左侧列表中选择的表中的行信息。
#### 4. 联系人提供者探索器的源代码
重要代码集中在 `PickFragment.java` 类中,以下是该类的部分代码及功能介绍:
```java
package com.enterpriseandroidbook.contactscontractexample;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;
import android.app.Activity;
import android.app.Fragment;
import android.app.ListFragment;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
public class PickFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor>, OnMenuItemClickListener {
// 控制日志开关
private static final boolean L = true;
// 用于日志记录的类名
private final String CLASSNAME = getClass().getSimpleName();
// 为加载器设置的 ID
public static final int LOADER_ID = 42;
// 保存状态的成员标签
private final String STATE_LABEL_NAME = "tablename";
// 当前表的类名
private String tableName;
public void onAttach(Activity activity) {
super.onAttach(activity);
// 通知片段与 Activity 关联
if (L)
Log.i(CLASSNAME, "onAttach " + activity.getClass().getSimpleName());
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 告知系统我们有选项菜单
setHasOptionsMenu(true);
doLoaderCreation(savedInstanceState);
// 通知
if (L)
Log.i(CLASSNAME, "onCreate");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final LinearLayout listLayout = (LinearLayout) inflater.inflate(
R.layout.list_frag_list, container, false);
if (L)
Log.i(CLASSNAME, "onCreateView");
return listLayout;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(STATE_LABEL_NAME, tableName);
}
public void onStart() {
super.onStart();
if (L)
Log.i(CLASSNAME, "onStart");
}
public void onResume() {
super.onResume();
if (L)
Log.i(CLASSNAME, "onResume");
}
public void onPause() {
super.onPause();
if (L)
Log.i(CLASSNAME, "onPause");
}
public void onStop() {
super.onStop();
if (L)
Log.i(CLASSNAME, "onStop");
}
public void onDestroyView() {
super.onDestroyView();
if (L)
Log.i(CLASSNAME, "onDestroyView");
}
public void onDestroy() {
super.onDestroy();
if (L)
Log.i(CLASSNAME, "onDestroy");
}
public void onDetach() {
super.onDetach();
if (L)
Log.i(CLASSNAME, "onDetach");
}
// 次要生命周期方法
public void onActivityCreated() {
// 通知包含的 Activity 及其视图层次结构存在
if (L)
Log.i(CLASSNAME, "onActivityCreated");
}
// 覆盖 Fragment 中 ComponentCallbacks 方法的实现
@Override
public void onConfigurationChanged(Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration);
// 除非在清单中声明处理的更改,否则不会发生此情况
if (L)
Log.i(CLASSNAME, "onConfigurationChanged");
}
@Override
public void onLowMemory() {
// 不能保证此方法在其他回调之前或之后被调用
if (L)
Log.i(CLASSNAME, "onLowMemory");
}
// 列表视图点击处理
public void onListItemClick(ListView l, View v, int position, long id) {
Cursor c = ((CursorAdapter) getListView().getAdapter()).getCursor();
String item = buildItemInfo(c, position);
String tableInfo = buildDatabaseInfo(c);
Bundle data = ((MainActivity) getActivity()).buildDataBundle(item,
tableInfo);
((TabbedActivity) getActivity()).loadTabFragments(data);
}
// 实现 Loader 回调接口
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(this.getActivity(), uriForTable(tableName),
null, null, null, null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
((SimpleCursorAdapter) getListAdapter()).swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> loader) {
((SimpleCursorAdapter) getListAdapter()).swapCursor(null);
}
// 应用特定代码
private final static String NL = System.getProperty("line.separator");
private void doLoaderCreation(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 如果没有保存的状态,从 Data 表开始
if (null == savedInstanceState) {
openNewTableByName("android.provider.ContactsContract$Data");
} else {
// 查看是否可以从保存的状态重新创建查询
tableName = savedInstanceState.getString(STATE_LABEL_NAME);
if (null == tableName) {
doLoaderCre
```
0
0
复制全文
相关推荐










