如何使用AsyncQueryHandler

如何使用AsyncQueryHandler

這次範例從Google Sample改寫。

這次會比較複雜一點
結合了如何寫一個電話簿(Phone book) (ContentResolver)以及如何使用RecylerView+CardView

public class MainActivity extends AppCompatActivity {
    private AsyncQueryHandler queryHandler;
    private List<Map<String, String>> contactsArrayList;
    private static final int NAME_TOKEN = 0;
    private static final int NUMBER_TOKEN = 1;
    private static final String NAME = "name";
    private static final String NUMBER = "number";
    private static final String[] NAME_PROJECTION = new String[]{
        ContactsContract.Contacts._ID,
            ContactsContract.Contacts.DISPLAY_NAME
    };
    private static final String[] PHONE_NUMBER_PROJECTION = new String[] {
            ContactsContract.CommonDataKinds.Phone._ID,
            ContactsContract.CommonDataKinds.Phone.NUMBER
    };
    private RecyclerView list;
    private RecyclerView.Adapter<MyAdapter.ViewHolder> adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
    }
    private void initView(){
        list = (RecyclerView) findViewById(R.id.list_view);
        final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        list.setLayoutManager(layoutManager);
        adapter = new MyAdapter(contactsArrayList);
        list.setAdapter(adapter);
    }
    private void initData(){
        contactsArrayList = new ArrayList<>();
        queryHandler = new MyAsyncQueryHandler(this);
        queryHandler.startQuery(NAME_TOKEN, null,
                ContactsContract.Contacts.CONTENT_URI,
                NAME_PROJECTION,
                ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1",
                null,
                null);

    }
    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
        private List<Map<String, String>> mData;

        public class ViewHolder extends RecyclerView.ViewHolder {
            public TextView name;
            public TextView phone;
            public ViewHolder(View v) {
                super(v);
                name = (TextView) v.findViewById(R.id.name);
                phone = (TextView) v.findViewById(R.id.phone);
            }
        }

        public MyAdapter(List<Map<String, String>> data) {
            mData = data;
        }

        @Override
        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item, parent, false);
            ViewHolder vh = new ViewHolder(v);
            return vh;
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            holder.name.setText(mData.get(position).get(NAME));
            holder.phone.setText(mData.get(position).get(NUMBER));
        }

        @Override
        public int getItemCount() {
            return mData.size();
        }
    }
    class MyAsyncQueryHandler extends AsyncQueryHandler {
        public MyAsyncQueryHandler(Context context) {
            super(context.getContentResolver());
        }

        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            super.onQueryComplete(token, cookie, cursor);
            switch(token){
                case NAME_TOKEN:
                    while (cursor.moveToNext()) {
                        Map<String, String> map = new HashMap<>();
                        String name = cursor.getString(cursor
                                .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                        Uri.Builder builder = ContactsContract.Contacts.CONTENT_URI.buildUpon();
                        ContentUris.appendId(builder, cursor.getLong(0));
                        builder.appendEncodedPath(ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
                        Uri phoneNumbersUri = builder.build();
                        queryHandler.startQuery(NUMBER_TOKEN, cursor.getPosition(), phoneNumbersUri,
                                PHONE_NUMBER_PROJECTION, ContactsContract.CommonDataKinds.Phone.MIMETYPE + "=?",
                                new String[] { ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE }, null);
                        map.put(NAME, name);
                        contactsArrayList.add(map);
                    }
                    break;
                case NUMBER_TOKEN:
                    while (cursor.moveToNext()) {
                        String phoneNumber = cursor.getString(cursor.getColumnIndex(
                                ContactsContract.CommonDataKinds.Phone.NUMBER));
                        int index = (Integer)cookie;
                        Map<String, String> map = contactsArrayList.get(index);
                        map.put(NUMBER, phoneNumber);
                        contactsArrayList.set(index, map);
                    }
                    adapter.notifyDataSetChanged();
                    break;
            }

        }
    }
}

MainActivity xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="personal.givemepass.asyncqueryhandlerdemo.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

RecyclerView item xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_gravity="center"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    card_view:cardCornerRadius="4dp"
    android:layout_margin="5dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:weightSum="2"
        android:orientation="vertical">

        <TextView
            android:layout_weight="1"
            android:id="@+id/name"
            android:textColor="#000000"
            android:textSize="24sp"
            android:gravity="center_horizontal"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_gravity="center"/>
        <TextView
            android:layout_weight="1"
            android:id="@+id/phone"
            android:textColor="#000000"
            android:textSize="24sp"
            android:gravity="center_horizontal"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_gravity="center"/>
    </LinearLayout>
</android.support.v7.widget.CardView>

記得加入Gradle

compile 'com.android.support:recyclerview-v7:23.0.1'
compile 'com.android.support:cardview-v7:+'

權限也要加

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CALL_PHONE" />



程式碼