কোনও পরিচিতির বিবরণ ফিরিয়ে আনা

এই টিউটোরিয়াল থেকে আপনি জানতে পারবেন যে কীভাবে কোনও পরিচিতির বিস্তারিত ডেটা যেমন ইমেল আইডি, ফোন নম্বর ইত্যাদি ফিরিয়ে আনা যায়। কোনও পরিচিতি ফিরিয়ে আনার সময় ব্যবহারকারীরা যে বিবরণ খোঁজেন এটি হল সেই বিবরণ। আপনি তাদের কোনও পরিচিতির সব বিবরণ দিতে পারেন অথবা শুধুমাত্র নির্দিষ্ট ধরনের বিবরণ দেখাতে পারেন, যেমন ইমেল আইডি।

এই টিউটোরিয়ালের ধাপগুলি ধরে নেয় যে ব্যবহারকারীর বেছে নেওয়া পরিচিতির জন্য আপনার কাছে আগে থেকেই একটি ContactsContract.Contacts সারি আছে। পরিচিতির নাম ফিরিয়ে আনা সংক্রান্ত টিউটোরিয়াল থেকে পরিচিতির তালিকা কীভাবে ফিরিয়ে আনতে হয় তা জানা যায়।

কোনও পরিচিতির সব বিবরণ ফিরিয়ে আনুন

কোনও পরিচিতির সব বিবরণ ফিরে পেতে, ContactsContract.Data টেবিলে এমন কোনও সারি সার্চ করুন যাতে পরিচিতির LOOKUP_KEY আছে। এই কলামটি ContactsContract.Data টেবিলে উপলভ্য কারণ Contacts Provider 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 রিট্রিভ করুন যাতে আপনি রিট্রিভ করা প্রতিটি সারির ডেটার ধরন শনাক্ত করতে পারেন। যেমন:

Kotlin

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 কলামটি ব্যবহার করুন। যেমন:

Kotlin

// 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. এই কোয়েরি আর্গুমেন্ট সব ইমেল সারিকে একসাথে, সব ফোন নম্বর সারিকে একসাথে এবং আরও অনেক কিছু গ্রুপ করে। যেমন:

Kotlin

/*
 * 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-এর মাধ্যমে ইটারেট করতে হবে, বর্তমান সারির ডেটার ধরন নির্ধারণ করতে হবে এবং সাবটাইপ ব্যবহার করে এমন সারির জন্য ডেটা স্টোর করতে হবে। কার্সর পড়া শেষ হলে, আপনি সাবটাইপ অনুযায়ী প্রতিটি ডেটার ধরন সাজাতে এবং ফলাফল দেখাতে পারবেন।

লোডার ইনিশিয়ালাইজ করা

সবসময় ব্যাকগ্রাউন্ড থ্রেডে Contacts Provider (এবং অন্যান্য সব কন্টেন্ট প্রোভাইডার) থেকে রিট্রিভ করুন। ব্যাকগ্রাউন্ডে ডেটা ফিরিয়ে আনতে LoaderManager ক্লাস এবং LoaderManager.LoaderCallbacks ইন্টারফেস দ্বারা সংজ্ঞায়িত লোডার ফ্রেমওয়ার্ক ব্যবহার করুন।

আপনি সারিগুলি পুনরুদ্ধার করার জন্য প্রস্তুত হলে, initLoader() কল করে লোডার ফ্রেমওয়ার্ক শুরু করুন। মেথডে একটি পূর্ণসংখ্যা শনাক্তকারী পাস করুন; এই শনাক্তকারীকে LoaderManager.LoaderCallbacks মেথডে পাস করা হয়। শনাক্তকারী আপনাকে একটি অ্যাপে একাধিক লোডার ব্যবহার করতে সাহায্য করে, কারণ এটি আপনাকে তাদের মধ্যে পার্থক্য করতে দেয়।

লোডার ফ্রেমওয়ার্ক কীভাবে শুরু করতে হয় তা নিম্নলিখিত স্নিপেট থেকে জানতে পারবেন:

Kotlin

// 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 টেবিল সার্চ করছেন, তাই কন্টেন্ট URI হিসেবে Data.CONTENT_URI কনস্ট্যান্ট ব্যবহার করুন। যেমন:

Kotlin

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() লোডার ফ্রেমওয়ার্ক কল করে। যেমন:

Kotlin

    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;
            ...
        }
    }

ফলাফলের ব্যাক-এন্ডে থাকা ডেটা Cursor পরিবর্তন হয়েছে বলে লোডার ফ্রেমওয়ার্ক শনাক্ত করলে, onLoaderReset() মেথডটি ইনভোক করা হয়। এই পর্যায়ে, Cursor-এর আগে থেকে থাকা রেফারেন্স নাল হিসেবে সেট করে সরিয়ে দিন। আপনি তা না করলে, লোডার ফ্রেমওয়ার্ক পুরনো Cursor নষ্ট করবে না এবং আপনার মেমরি লিক হবে। যেমন:

Kotlin

    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 ভ্যালু সার্চ করার জন্য বেছে নেওয়া টেক্সট পরিবর্তন করুন।
সাজানোর ক্রম
আপনি যেহেতু শুধুমাত্র একটি বিবরণের ধরন বেছে নিচ্ছেন, তাই Data.MIMETYPE অনুযায়ী ফেরত আসা Cursor গ্রুপ করবেন না।

এইসব পরিবর্তন নিম্নলিখিত বিভাগে বর্ণনা করা হয়েছে।

প্রোজেকশন নির্দিষ্ট করুন

ডেটার ধরনের জন্য ContactsContract.CommonDataKinds-এর সাবক্লাসে কলামের নামের কনস্ট্যান্ট ব্যবহার করে, আপনি যে কলামগুলি রিট্রিভ করতে চান সেগুলি সংজ্ঞায়িত করুন। আপনি যদি Cursor-কে ListView-এর সাথে বাইন্ড করার পরিকল্পনা করেন, তাহলে _ID কলামটি ফিরিয়ে আনতে ভুলবেন না। যেমন, ইমেল ডেটা ফিরিয়ে আনতে, নিম্নলিখিত প্রোজেকশন নির্ধারণ করুন:

Kotlin

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 ভ্যালুকে সিঙ্গেল কোটের মধ্যে রাখুন, এর জন্য কনস্ট্যান্টের শুরুতে ও শেষে "'" (সিঙ্গেল কোট) ক্যারেক্টার যোগ করুন; তা না হলে, প্রদানকারী কনস্ট্যান্টকে স্ট্রিং ভ্যালু হিসেবে না দেখে ভেরিয়েবলের নাম হিসেবে দেখবেন। এই ভ্যালুর জন্য আপনাকে কোনও প্লেসহোল্ডার ব্যবহার করতে হবে না, কারণ আপনি ব্যবহারকারীর দেওয়া ভ্যালুর পরিবর্তে একটি ধ্রুবক ব্যবহার করছেন। যেমন:

Kotlin

/*
 * 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-এর ভিত্তিতে সাজাতে পারবেন:

Kotlin

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

জাভা

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