这个demeo主要演示的是使内容提供者和内容解析者来获取其它应用的数据。Content Provider为不同应用之间共享数据提供了统一的接口,Android系统的每个Content Provider都定义了一个CONTENT_URI,Android中每个Context对象(如Activity)对含有一个ContentResolver,ContentResolver可以根据CONTENT_URI获取对应的Content Provider。
在本例中使用了startManagingCursor(c);对cursor进行托管,但在android3.0以后推出了更为安全和灵活的cursor管理方式,即使用LoaderManager,本例就是在原有的基础上进行了改造,使用LoaderManager来完成这个demo。
在本例中让ManiActivity继承了ListActivity,所以需要去掉setContentView(),不然会报错。
activity_main.xml只做为了listActivity的每个条目的布局。在这里使用了QuickContactBadge组件,该组件继承ImageView,用于显示联系人左侧的图标。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="5dp">
<QuickContactBadge
android:id="@+id/badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_launcher"
style="?android:attr/quickContactBadgeStyleSmallWindowSmall"/>
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
android:layout_marginLeft="10dp"
android:layout_gravity="center_vertical" />
</LinearLayout>
MainActivity:这里使用了ResourceCursorAdapter的子类作为listActivity的适配器。
public class MainActivity extends ListActivity {
// 定义需要从联系人中取出的列
private final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,// 0
Contacts.DISPLAY_NAME,// 1
Contacts.STARRED,// 2
Contacts.TIMES_CONTACTED,// 3
Contacts.CONTACT_PRESENCE,// 4
Contacts.PHOTO_ID,// 5
Contacts.LOOKUP_KEY,// 6
Contacts.HAS_PHONE_NUMBER // 7
};
private static final int SUMMARY_ID_COLUMN_INDEX = 0;
private static final int SUMMARY_NAME_COLUMN_INDEX = 1;
private static final int SUMMARY_STARRED_COLUMN_INDEX = 2;
private static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 3;
private static final int SUMMARY_CONTACT_PRESENCE_COLUMN_INDEX = 4;
private static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 5;
private static final int SUMMARY_LOOKUP_KEY_COLUMN_INDEX = 6;
private static final int SUMMARY_HAS_PHONE_NUMBER_COLUMN_INDEX = 7;
private static final int LOADER_ID = 1;
private String selection;
private ContactListItemAdapter adapter;
/**
* android 3.0以后提供了更加安全和灵活的对数据进行异步加载的方式,就是使用LoaderManager
* 通过它可以轻松地实现对cursor的管理
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
selection = "((" + Contacts.DISPLAY_NAME + " NOTNULL) And ("
+ Contacts.DISPLAY_NAME + "!='') And ("
+ Contacts.HAS_PHONE_NUMBER + "=1))";
// flags 这个标志用来决定该适配器的行为。(Android3.0推荐我们传递
// CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER。设置标志用来添加一个
// 监听器,监听着参数cursor的数据是否有更变。)
adapter = new ContactListItemAdapter(MainActivity.this,
R.layout.activity_main, null,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
// 获取LoaderManager
LoaderManager manager = getLoaderManager();
// 初始化loader对象
manager.initLoader(LOADER_ID, null, MyLoader);
//将游标交给activity托管 startManagingCursor(c);
}
private LoaderCallbacks<Cursor> MyLoader = new LoaderCallbacks<Cursor>() {
// 创建一个loader对象,该对象携带游标
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// 创建cursorloader对象第二个参数为内容提供者的Uri,第三个参数为
// 要查询出哪些列,第四个参数指定查询的条件,第五个参数为查询的参数,
// 最后一个参数表示 按本地语言的名字降序进行排序
CursorLoader cl = new CursorLoader(MainActivity.this,
Contacts.CONTENT_URI, CONTACTS_SUMMARY_PROJECTION,
selection, null, Contacts.DISPLAY_NAME
+ " COLLATE LOCALIZED ASC");
return cl;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (loader.getId() == LOADER_ID) {
if (cursor == null) {
Toast.makeText(MainActivity.this, "查询失败!", 0).show();
return;
}
if (cursor.getCount() == 0) {
Toast.makeText(MainActivity.this, "查询结果为空!", 0).show();
}
// 更新UI信息
/*
* 使用内容解析者根据联系人的URI对联系人进行查询,第一个参数为联系人Uri,第二个参数为
* 要查询出哪些列,第三个参数指定查询的条件,第四个参数为查询的参数,最后一个参数表示 按本地语言的名字降序进行排序
*/
Cursor c = getContentResolver().query(Contacts.CONTENT_URI,
CONTACTS_SUMMARY_PROJECTION, selection, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
adapter.swapCursor(c);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
Log.i("TAG", "loader was reseted");
}
};
private class ContactListItemAdapter extends ResourceCursorAdapter {
public ContactListItemAdapter(Context context, int layout, Cursor c,
int flags) {
super(context, layout, c, flags);
}
/**
* 找到各个组件
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = super.newView(context, cursor, parent);
ContactListItemCache cache = new ContactListItemCache();
cache.nameView = (TextView) view.findViewById(R.id.tv_name);
cache.badge = (QuickContactBadge) view.findViewById(R.id.badge);
view.setTag(cache);
return view;
}
/**
* 为组件赋值
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
ContactListItemCache cache = (ContactListItemCache) view.getTag();
// 将当前查询到的名字复制到可变长度数组中
cursor.copyStringToBuffer(SUMMARY_NAME_COLUMN_INDEX,
cache.nameBuffer);
int size = cache.nameBuffer.sizeCopied;
cache.nameView.setText(cache.nameBuffer.data, 0, size);
// 为quickContactBadge赋值
long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
String lookupKey = cursor
.getString(SUMMARY_LOOKUP_KEY_COLUMN_INDEX);
Uri lookupUri = Contacts.getLookupUri(contactId,lookupKey);
//System.out.println("=====:"+lookupUri.toString());
// 指定和QuickContactBadge关联的联系人URI
cache.badge.assignContactUri(lookupUri);
}
private class ContactListItemCache {
public TextView nameView;
public QuickContactBadge badge;
// 构造一个可变长度的字符数组
public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
}
}
}
最后就是需要在配置文件中设置读取系统联系人的权限:
<uses-permission android:name="android.permission.READ_CONTACTS"/>