جزئیات یک مخاطب را بازیابی کنید

این درس نحوه بازیابی اطلاعات جزییات یک مخاطب مانند آدرس ایمیل، شماره تلفن و غیره را نشان می دهد. این جزئیاتی است که کاربران هنگام بازیابی یک مخاطب به دنبال آن هستند. می توانید تمام جزئیات یک مخاطب را به آنها بدهید یا فقط جزئیات یک نوع خاص مانند آدرس ایمیل را نمایش دهید.

مراحل این درس فرض می کند که شما از قبل یک ردیف ContactsContract.Contacts برای مخاطبی که کاربر انتخاب کرده است دارید. درس بازیابی نام مخاطبین نحوه بازیابی لیستی از مخاطبین را نشان می دهد.

تمام جزئیات یک مخاطب را بازیابی کنید

برای بازیابی همه جزئیات یک مخاطب، جدول ContactsContract.Data را برای هر ردیفی که حاوی LOOKUP_KEY مخاطب است جستجو کنید. این ستون در جدول ContactsContract.Data موجود است، زیرا ارائه دهنده Contacts یک اتصال ضمنی بین جدول ContactsContract.Contacts و جدول ContactsContract.Data ایجاد می کند. ستون LOOKUP_KEY با جزئیات بیشتر در درس بازیابی نام مخاطبین توضیح داده شده است.

توجه: بازیابی تمام جزئیات برای یک مخاطب، عملکرد دستگاه را کاهش می دهد، زیرا باید تمام ستون های جدول ContactsContract.Data را بازیابی کند. قبل از استفاده از این تکنیک تأثیر عملکرد را در نظر بگیرید.

درخواست مجوزها

برای خواندن از ارائه دهنده مخاطبین، برنامه شما باید مجوز READ_CONTACTS داشته باشد. برای درخواست این مجوز، عنصر فرزند زیر <manifest> را به فایل مانیفست خود اضافه کنید:

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

یک پروجکشن تنظیم کنید

بسته به نوع داده ای که یک ردیف دارد، ممکن است فقط از چند یا چند ستون استفاده کند. علاوه بر این، داده ها بسته به نوع داده در ستون های مختلف قرار دارند. برای اطمینان از دریافت تمام ستون‌های ممکن برای همه انواع داده‌های ممکن، باید همه نام ستون‌ها را به طرح خود اضافه کنید. اگر Cursor نتیجه را به ListView متصل می کنید، همیشه Data._ID بازیابی کنید. در غیر این صورت، اتصال کار نخواهد کرد. همچنین Data.MIMETYPE را بازیابی کنید تا بتوانید نوع داده هر ردیفی را که بازیابی می کنید شناسایی کنید. به عنوان مثال:

کاتلین

private val PROJECTION: Array<out String> = arrayOf(
        ContactsContract.Data._ID,
        ContactsContract.Data.MIMETYPE,
        ContactsContract.Data.DATA1,
        ContactsContract.Data.DATA2,
        ContactsContract.Data.DATA3,
        ContactsContract.Data.DATA4,
        ContactsContract.Data.DATA5,
        ContactsContract.Data.DATA6,
        ContactsContract.Data.DATA7,
        ContactsContract.Data.DATA8,
        ContactsContract.Data.DATA9,
        ContactsContract.Data.DATA10,
        ContactsContract.Data.DATA11,
        ContactsContract.Data.DATA12,
        ContactsContract.Data.DATA13,
        ContactsContract.Data.DATA14,
        ContactsContract.Data.DATA15
)

جاوا

    private static final String[] PROJECTION =
            {
                ContactsContract.Data._ID,
                ContactsContract.Data.MIMETYPE,
                ContactsContract.Data.DATA1,
                ContactsContract.Data.DATA2,
                ContactsContract.Data.DATA3,
                ContactsContract.Data.DATA4,
                ContactsContract.Data.DATA5,
                ContactsContract.Data.DATA6,
                ContactsContract.Data.DATA7,
                ContactsContract.Data.DATA8,
                ContactsContract.Data.DATA9,
                ContactsContract.Data.DATA10,
                ContactsContract.Data.DATA11,
                ContactsContract.Data.DATA12,
                ContactsContract.Data.DATA13,
                ContactsContract.Data.DATA14,
                ContactsContract.Data.DATA15
            };

این طرح همه ستون ها را برای یک ردیف در جدول ContactsContract.Data با استفاده از نام ستون های تعریف شده در کلاس ContactsContract.Data بازیابی می کند.

به صورت اختیاری، می توانید از هر ثابت ستون دیگری که در کلاس ContactsContract.Data تعریف شده یا به ارث رسیده است استفاده کنید. با این حال، توجه داشته باشید که ستون های SYNC1 تا SYNC4 برای استفاده توسط آداپتورهای همگام سازی قرار دارند، بنابراین داده های آنها مفید نیست.

معیارهای انتخاب را مشخص کنید

یک ثابت برای عبارت انتخابی خود، یک آرایه برای نگهداری آرگومان های انتخابی و یک متغیر برای نگهداری مقدار انتخاب تعریف کنید. از ستون Contacts.LOOKUP_KEY برای پیدا کردن مخاطب استفاده کنید. به عنوان مثال:

کاتلین

// Defines the selection clause
private const val SELECTION: String = "${ContactsContract.Data.LOOKUP_KEY} = ?"
...
// Defines the array to hold the search criteria
private val selectionArgs: Array<String> = arrayOf("")
/*
 * Defines a variable to contain the selection value. Once you
 * have the Cursor from the Contacts table, and you've selected
 * the desired row, move the row's LOOKUP_KEY value into this
 * variable.
 */
private var lookupKey: String? = null

جاوا

    // Defines the selection clause
    private static final String SELECTION = Data.LOOKUP_KEY + " = ?";
    // Defines the array to hold the search criteria
    private String[] selectionArgs = { "" };
    /*
     * Defines a variable to contain the selection value. Once you
     * have the Cursor from the Contacts table, and you've selected
     * the desired row, move the row's LOOKUP_KEY value into this
     * variable.
     */
    private lateinit var lookupKey: String

با استفاده از "?" به عنوان یک مکان نگهدار در عبارت متن انتخابی شما تضمین می کند که جستجوی حاصل از طریق اتصال به جای کامپایل SQL ایجاد می شود. این رویکرد امکان تزریق مخرب SQL را از بین می برد.

ترتیب مرتب سازی را تعریف کنید

ترتیب مرتب سازی مورد نظر خود را در Cursor به دست آمده تعریف کنید. برای نگه داشتن تمام ردیف‌های یک نوع داده خاص، بر اساس Data.MIMETYPE مرتب کنید. این آرگومان پرس و جو همه ردیف های ایمیل، همه ردیف های تلفن را با هم و غیره گروه بندی می کند. به عنوان مثال:

کاتلین

/*
 * Defines a string that specifies a sort order of MIME type
 */
private const val SORT_ORDER = ContactsContract.Data.MIMETYPE

جاوا

    /*
     * Defines a string that specifies a sort order of MIME type
     */
    private static final String SORT_ORDER = ContactsContract.Data.MIMETYPE;

توجه: برخی از انواع داده ها از یک نوع فرعی استفاده نمی کنند، بنابراین نمی توانید بر اساس نوع فرعی مرتب کنید. درعوض، باید از طریق Cursor برگشتی تکرار کنید، نوع داده ردیف فعلی را تعیین کنید و داده‌ها را برای ردیف‌هایی که از یک نوع فرعی استفاده می‌کنند ذخیره کنید. پس از پایان خواندن مکان نما، می توانید هر نوع داده را بر اساس نوع فرعی مرتب کنید و نتایج را نمایش دهید.

Loader را مقداردهی اولیه کنید

همیشه از ارائه دهنده مخاطبین (و سایر ارائه دهندگان محتوا) در یک رشته پس زمینه بازیابی کنید. از چارچوب Loader تعریف شده توسط کلاس LoaderManager و رابط LoaderManager.LoaderCallbacks برای انجام بازیابی پس زمینه استفاده کنید.

هنگامی که آماده بازیابی ردیف ها هستید، با فراخوانی initLoader() چارچوب لودر را مقداردهی اولیه کنید. یک شناسه عدد صحیح را به متد ارسال کنید. این شناسه به روش های LoaderManager.LoaderCallbacks ارسال می شود. شناسه به شما کمک می کند تا از چندین بارگذار در یک برنامه استفاده کنید و به شما امکان می دهد بین آنها تفاوت قائل شوید.

قطعه زیر نحوه اولیه سازی چارچوب لودر را نشان می دهد:

کاتلین

// Defines a constant that identifies the loader
private const val DETAILS_QUERY_ID: Int = 0

class DetailsFragment : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // Initializes the loader framework
        loaderManager.initLoader(DETAILS_QUERY_ID, null, this)

جاوا

public class DetailsFragment extends Fragment implements
        LoaderManager.LoaderCallbacks<Cursor> {
    ...
    // Defines a constant that identifies the loader
    static int DETAILS_QUERY_ID = 0;
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        // Initializes the loader framework
        getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);

پیاده سازی onCreateLoader()

متد onCreateLoader() را پیاده سازی کنید که بلافاصله پس از فراخوانی initLoader() توسط فریم ورک لودر فراخوانی می شود. یک CursorLoader از این روش برگردانید. از آنجایی که در حال جستجوی جدول ContactsContract.Data هستید، Data.CONTENT_URI ثابت به عنوان URI محتوا استفاده کنید. به عنوان مثال:

کاتلین

override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
    // Choose the proper action
    mLoader = when(loaderId) {
        DETAILS_QUERY_ID -> {
            // Assigns the selection parameter
            selectionArgs[0] = lookupKey
            // Starts the query
            activity?.let {
                CursorLoader(
                        it,
                        ContactsContract.Data.CONTENT_URI,
                        PROJECTION,
                        SELECTION,
                        selectionArgs,
                        SORT_ORDER
                )
            }
        }
        ...
    }
    return mLoader
}

جاوا

@Override
    public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
        // Choose the proper action
        switch (loaderId) {
            case DETAILS_QUERY_ID:
            // Assigns the selection parameter
            selectionArgs[0] = lookupKey;
            // Starts the query
            CursorLoader mLoader =
                    new CursorLoader(
                            getActivity(),
                            ContactsContract.Data.CONTENT_URI,
                            PROJECTION,
                            SELECTION,
                            selectionArgs,
                            SORT_ORDER
                    );
    }

پیاده سازی onLoadFinished() و onLoaderReset()

متد onLoadFinished() را پیاده سازی کنید. فریم ورک لودر onLoadFinished() زمانی فراخوانی می‌کند که ارائه‌دهنده تماس‌ها نتایج پرس و جو را برمی‌گرداند. به عنوان مثال:

کاتلین

    override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) {
        when(loader.id) {
            DETAILS_QUERY_ID -> {
                /*
                 * Process the resulting Cursor here.
                 */
            }
            ...
        }
    }

جاوا

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        switch (loader.getId()) {
            case DETAILS_QUERY_ID:
                    /*
                     * Process the resulting Cursor here.
                     */
                }
                break;
            ...
        }
    }

متد onLoaderReset() زمانی فراخوانی می‌شود که چارچوب لودر تشخیص دهد که داده‌های پشتیبان Cursor نتیجه تغییر کرده است. در این مرحله، هرگونه ارجاع موجود به Cursor با قرار دادن null حذف کنید. اگر این کار را نکنید، چارچوب لودر Cursor قدیمی را از بین نمی برد و با نشت حافظه مواجه خواهید شد. به عنوان مثال:

کاتلین

    override fun onLoaderReset(loader: Loader<Cursor>) {
        when (loader.id) {
            DETAILS_QUERY_ID -> {
                /*
                 * If you have current references to the Cursor,
                 * remove them here.
                 */
            }
            ...
        }
    }

جاوا

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        switch (loader.getId()) {
            case DETAILS_QUERY_ID:
                /*
                 * If you have current references to the Cursor,
                 * remove them here.
                 */
                }
                break;
    }

جزئیات خاص یک مخاطب را بازیابی کنید

بازیابی یک نوع داده خاص برای یک مخاطب، مانند همه ایمیل ها، از همان الگوی بازیابی همه جزئیات پیروی می کند. اینها تنها تغییراتی هستند که باید در کد فهرست شده در بازیابی همه جزئیات برای یک مخاطب ایجاد کنید:

فرافکنی
طرح خود را برای بازیابی ستون هایی که مختص نوع داده هستند، تغییر دهید. همچنین پروجکشن را تغییر دهید تا از ثابت های نام ستون تعریف شده در زیر کلاس ContactsContract.CommonDataKinds مربوط به نوع داده استفاده کند.
انتخاب
متن انتخابی را برای جستجوی مقدار MIMETYPE که مخصوص نوع داده شما است، تغییر دهید.
ترتیب مرتب سازی
از آنجایی که فقط یک نوع جزئیات را انتخاب می‌کنید، Cursor بازگشتی را براساس Data.MIMETYPE گروه‌بندی نکنید.

این تغییرات در بخش های زیر توضیح داده شده است.

فرافکنی را تعریف کنید

ستون هایی را که می خواهید بازیابی کنید، با استفاده از ثابت های نام ستون در زیر کلاس ContactsContract.CommonDataKinds برای نوع داده تعریف کنید. اگر قصد دارید Cursor خود را به ListView متصل کنید، حتماً ستون _ID را بازیابی کنید. به عنوان مثال، برای بازیابی اطلاعات ایمیل، طرح زیر را تعریف کنید:

کاتلین

private val PROJECTION: Array<String> = arrayOf(
        ContactsContract.CommonDataKinds.Email._ID,
        ContactsContract.CommonDataKinds.Email.ADDRESS,
        ContactsContract.CommonDataKinds.Email.TYPE,
        ContactsContract.CommonDataKinds.Email.LABEL
)

جاوا

    private static final String[] PROJECTION =
            {
                ContactsContract.CommonDataKinds.Email._ID,
                ContactsContract.CommonDataKinds.Email.ADDRESS,
                ContactsContract.CommonDataKinds.Email.TYPE,
                ContactsContract.CommonDataKinds.Email.LABEL
            };

توجه داشته باشید که این طرح از نام ستون های تعریف شده در کلاس ContactsContract.CommonDataKinds.Email به جای نام ستون های تعریف شده در کلاس ContactsContract.Data استفاده می کند. استفاده از نام ستون های خاص ایمیل، کد را خواناتر می کند.

در طرح ریزی، می توانید از هر یک از ستون های دیگر تعریف شده در زیر کلاس ContactsContract.CommonDataKinds نیز استفاده کنید.

معیارهای انتخاب را تعریف کنید

یک عبارت متن جستجو را تعریف کنید که ردیف‌هایی را برای LOOKUP_KEY یک مخاطب خاص و Data.MIMETYPE جزئیات مورد نظر شما بازیابی می‌کند. مقدار MIMETYPE را با الحاق یک کاراکتر " ' " (تک نقل قول) به ابتدا و انتهای ثابت در گیومه های تکی قرار دهید. در غیر این صورت، ارائه دهنده ثابت را به عنوان یک نام متغیر به جای یک مقدار رشته تفسیر می کند. برای این مقدار نیازی به استفاده از نگهدارنده مکان ندارید، زیرا از یک مقدار ثابت به جای یک مقدار عرضه شده توسط کاربر استفاده می کنید. به عنوان مثال:

کاتلین

/*
 * Defines the selection clause. Search for a lookup key
 * and the Email MIME type
 */
private const val SELECTION =
        "${ContactsContract.Data.LOOKUP_KEY} = ? AND " +
        "${ContactsContract.Data.MIMETYPE} = '${Email.CONTENT_ITEM_TYPE}'"
...
// Defines the array to hold the search criteria
private val selectionArgs: Array<String> = arrayOf("")

جاوا

    /*
     * Defines the selection clause. Search for a lookup key
     * and the Email MIME type
     */
    private static final String SELECTION =
            Data.LOOKUP_KEY + " = ?" +
            " AND " +
            Data.MIMETYPE + " = " +
            "'" + Email.CONTENT_ITEM_TYPE + "'";
    // Defines the array to hold the search criteria
    private String[] selectionArgs = { "" };

ترتیب مرتب سازی را تعریف کنید

یک ترتیب مرتب سازی برای Cursor برگشتی تعریف کنید. از آنجایی که در حال بازیابی یک نوع داده خاص هستید، مرتب سازی در MIMETYPE را حذف کنید. در عوض، اگر نوع داده‌های جزییاتی که جستجو می‌کنید شامل یک نوع فرعی است، آن را مرتب کنید. به عنوان مثال، برای داده های ایمیل می توانید بر اساس Email.TYPE مرتب کنید:

کاتلین

private const val SORT_ORDER: String = "${Email.TYPE} ASC"

جاوا

    private static final String SORT_ORDER = Email.TYPE + " ASC ";