Android Api Demos登顶之路(十四)Quick Contacts

皮弘博
2023-12-01

这个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"/>
 类似资料: