পরিচিতির তালিকা রিট্রিভ করা

এই টিউটোরিয়াল থেকে আপনি জানতে পারবেন যে কীভাবে নিম্নলিখিত কৌশল ব্যবহার করে এমন পরিচিতির তালিকা ফিরিয়ে আনা যায় যাদের ডেটা সার্চ স্ট্রিংয়ের সম্পূর্ণ বা আংশিক অংশের সাথে মিলে যায়:

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

মনে রাখবেন: এই পাঠের সব উদাহরণে Contacts Provider থেকে ডেটা ফিরিয়ে আনতে CursorLoader ব্যবহার করা হয়। CursorLoader তার কোয়েরি এমন একটি থ্রেডে রান করে যা UI থ্রেড থেকে আলাদা। এটি নিশ্চিত করে যে কোয়েরি UI রেসপন্স টাইমকে ধীর করে দেয় না এবং ব্যবহারকারীর অভিজ্ঞতা খারাপ করে না। আরও তথ্যের জন্য, Android ট্রেনিং ক্লাস ব্যাকগ্রাউন্ডে ডেটা লোড করা দেখুন।

পরিষেবা প্রদানকারীর তথ্য পড়ার অনুমতি পাওয়ার জন্য অনুরোধ করুন

পরিচিতি প্রদানকারীকে কোনও ধরনের সার্চ করতে, আপনার অ্যাপের কাছে অবশ্যই READ_CONTACTS অনুমতি থাকতে হবে। এর জন্য অনুরোধ করতে, এই <uses-permission> এলিমেন্টটি আপনার ম্যানিফেস্ট ফাইলে <manifest>-এর চাইল্ড এলিমেন্ট হিসেবে যোগ করুন:

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

নাম অনুযায়ী পরিচিতি মেলান এবং ফলাফল তালিকাভুক্ত করুন

এই টেকনিক, কন্ট্যাক্ট প্রোভাইডারের ContactsContract.Contacts টেবিলে থাকা এক বা একাধিক পরিচিতির নামের সাথে সার্চ স্ট্রিং ম্যাচ করার চেষ্টা করে। আপনি সাধারণত চান যে ফলাফলগুলি ListView-এ দেখানো হোক, যাতে ব্যবহারকারী ম্যাচ করা পরিচিতিগুলির মধ্যে থেকে বেছে নিতে পারেন।

ListView এবং আইটেম লেআউট সংজ্ঞায়িত করুন

ListView-এ সার্চ ফলাফল দেখাতে, আপনার একটি মূল লেআউট ফাইল প্রয়োজন যা ListView সহ সম্পূর্ণ UI নির্ধারণ করে এবং একটি আইটেম লেআউট ফাইল যা ListView-এর একটি লাইন নির্ধারণ করে। যেমন, আপনি নিম্নলিখিত XML সহ প্রধান লেআউট ফাইল res/layout/contacts_list_view.xml তৈরি করতে পারেন:

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@android:id/list"
          android:layout_width="match_parent"
          android:layout_height="match_parent"/>

এই XML বিল্ট-ইন Android ListView উইজেট android:id/list ব্যবহার করে।

নিম্নলিখিত XML সহ আইটেম লেআউট ফাইল contacts_list_item.xml নির্ধারণ করুন:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@android:id/text1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:clickable="true"/>

এই XML বিল্ট-ইন Android TextView উইজেট android:text1 ব্যবহার করে।

মনে রাখবেন: এই পাঠে ব্যবহারকারীর থেকে সার্চ স্ট্রিং পাওয়ার জন্য UI-এর বিবরণ দেওয়া নেই, কারণ আপনি পরোক্ষভাবে স্ট্রিং পেতে চাইতে পারেন। যেমন, আপনি ব্যবহারকারীকে এমন পরিচিতি সার্চ করার বিকল্প দিতে পারেন যাদের নাম ইনকামিং টেক্সট মেসেজের স্ট্রিংয়ের সাথে ম্যাচ করে।

আপনার লেখা দুটি লেআউট ফাইল এমন একটি ইউজার ইন্টারফেসকে সংজ্ঞায়িত করে যা একটি ListViewদেখায়। পরবর্তী ধাপ হল এমন কোড লেখা যা এই UI ব্যবহার করে পরিচিতির তালিকা দেখায়।

পরিচিতির তালিকা দেখায় এমন একটি ফ্র্যাগমেন্ট নির্ধারণ করুন

পরিচিতির তালিকা দেখাতে, প্রথমে একটি Fragment নির্ধারণ করুন যা Activity-এর মাধ্যমে লোড করা হয়। Fragment ব্যবহার করা আরও নমনীয় টেকনিক, কারণ আপনি তালিকা দেখানোর জন্য একটি Fragment এবং ব্যবহারকারী তালিকা থেকে যে পরিচিতি বেছে নেবেন তার বিবরণ দেখানোর জন্য দ্বিতীয় Fragment ব্যবহার করতে পারবেন। এই পদ্ধতি ব্যবহার করে, আপনি এই টিউটোরিয়ালে দেখানো কোনও একটি টেকনিকের সাথে পরিচিতির বিবরণ ফিরিয়ে আনুন টিউটোরিয়ালের কোনও একটি টেকনিক একত্রিত করতে পারবেন।

Fragment থেকে এক বা একাধিক অবজেক্ট কীভাবে ব্যবহার করতে হয় তা জানতে Activity, ট্রেনিং ক্লাস ফ্র্যাগমেন্টের সাহায্যে ডায়নামিক UI তৈরি করুন পড়ুন।

পরিচিতি প্রদানকারীর বিরুদ্ধে কোয়েরি লেখার ব্যাপারে আপনাকে সাহায্য করতে, Android ফ্রেমওয়ার্ক ContactsContract নামের একটি কন্ট্র্যাক্ট ক্লাস প্রদান করে, যা প্রদানকারীকে অ্যাক্সেস করার জন্য উপযোগী কনস্ট্যান্ট ও মেথড নির্ধারণ করে। এই ক্লাস ব্যবহার করলে, কন্টেন্ট URI, টেবিলের নাম বা কলামের জন্য আপনাকে নিজস্ব কনস্ট্যান্ট সংজ্ঞায়িত করতে হবে না। এই ক্লাস ব্যবহার করতে, নিচের বিবৃতি অন্তর্ভুক্ত করুন:

Kotlin

import android.provider.ContactsContract

জাভা

import android.provider.ContactsContract;

যেহেতু কোডটি প্রদানকারীর থেকে CursorLoader ডেটা রিট্রিভ করতে LoaderManager.LoaderCallbacks ব্যবহার করে, তাই আপনাকে অবশ্যই উল্লেখ করতে হবে যে এটি লোডার ইন্টারফেস ইমপ্লিমেন্ট করে। এছাড়াও, সার্চ ফলাফলের তালিকা থেকে ব্যবহারকারী কোন পরিচিতি বেছে নিয়েছেন তা শনাক্ত করতে, অ্যাডাপ্টার ইন্টারফেস AdapterView.OnItemClickListener প্রয়োগ করুন। যেমন:

Kotlin

...
import android.support.v4.app.Fragment
import android.support.v4.app.LoaderManager
import android.widget.AdapterView
...
class ContactsFragment :
        Fragment(),
        LoaderManager.LoaderCallbacks<Cursor>,
        AdapterView.OnItemClickListener {

জাভা

...
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.widget.AdapterView;
...
public class ContactsFragment extends Fragment implements
        LoaderManager.LoaderCallbacks<Cursor>,
        AdapterView.OnItemClickListener {

গ্লোবাল ভেরিয়েবেল সংজ্ঞায়িত করুন

কোডের অন্যান্য অংশে ব্যবহৃত গ্লোবাল ভেরিয়েবেলগুলি সংজ্ঞায়িত করুন:

Kotlin

...
/*
 * Defines an array that contains column names to move from
 * the Cursor to the ListView.
 */
@SuppressLint("InlinedApi")
private val FROM_COLUMNS: Array<String> = arrayOf(
        if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) {
            ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
        } else {
            ContactsContract.Contacts.DISPLAY_NAME
        }
)
/*
 * Defines an array that contains resource ids for the layout views
 * that get the Cursor column contents. The id is pre-defined in
 * the Android framework, so it is prefaced with "android.R.id"
 */
private val TO_IDS: IntArray = intArrayOf(android.R.id.text1)
...
class ContactsFragment :
        Fragment(),
        LoaderManager.LoaderCallbacks<Cursor>,
        AdapterView.OnItemClickListener {
    ...
    // Define global mutable variables
    // Define a ListView object
    lateinit var contactsList: ListView
    // Define variables for the contact the user selects
    // The contact's _ID value
    var contactId: Long = 0
    // The contact's LOOKUP_KEY
    var contactKey: String? = null
    // A content URI for the selected contact
    var contactUri: Uri? = null
    // An adapter that binds the result Cursor to the ListView
    private val cursorAdapter: SimpleCursorAdapter? = null

জাভা

    ...
    /*
     * Defines an array that contains column names to move from
     * the Cursor to the ListView.
     */
    @SuppressLint("InlinedApi")
    private final static String[] FROM_COLUMNS = {
            Build.VERSION.SDK_INT
                    >= Build.VERSION_CODES.HONEYCOMB ?
                    ContactsContract.Contacts.DISPLAY_NAME_PRIMARY :
                    ContactsContract.Contacts.DISPLAY_NAME
    };
    /*
     * Defines an array that contains resource ids for the layout views
     * that get the Cursor column contents. The id is pre-defined in
     * the Android framework, so it is prefaced with "android.R.id"
     */
    private final static int[] TO_IDS = {
           android.R.id.text1
    };
    // Define global mutable variables
    // Define a ListView object
    ListView contactsList;
    // Define variables for the contact the user selects
    // The contact's _ID value
    long contactId;
    // The contact's LOOKUP_KEY
    String contactKey;
    // A content URI for the selected contact
    Uri contactUri;
    // An adapter that binds the result Cursor to the ListView
    private SimpleCursorAdapter cursorAdapter;
    ...

মনে রাখবেন: যেহেতু Contacts.DISPLAY_NAME_PRIMARY-এর জন্য Android 3.0 (API ভার্সন ১১) বা তার পরবর্তী ভার্সন প্রয়োজন, তাই আপনার অ্যাপের minSdkVersion ১০ বা তার কম সেট করলে Android Studio-তে Android Lint সংক্রান্ত সতর্কতা তৈরি হয়। এই সতর্কতা বন্ধ করতে, FROM_COLUMNS-এর সংজ্ঞার আগে @SuppressLint("InlinedApi") অ্যানোটেশন যোগ করুন।

ফ্র্যাগমেন্ট শুরু করুন

Fragment চালু করুন। Android সিস্টেমের জন্য প্রয়োজনীয় খালি, পাবলিক কনস্ট্রাক্টর যোগ করুন এবং কলব্যাক পদ্ধতি onCreateView()-এ Fragment অবজেক্টের UI ইনফ্লেট করুন। যেমন:

Kotlin

    // A UI Fragment must inflate its View
    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        // Inflate the fragment layout
        return inflater.inflate(R.layout.contact_list_fragment, container, false)
    }

জাভা

    // Empty public constructor, required by the system
    public ContactsFragment() {}

    // A UI Fragment must inflate its View
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the fragment layout
        return inflater.inflate(R.layout.contact_list_fragment,
            container, false);
    }

ListView-এর জন্য CursorAdapter সেট-আপ করুন

SimpleCursorAdapter সেট-আপ করুন যা সার্চের ফলাফলকে ListView-এর সাথে বাইন্ড করে। পরিচিতি দেখায় এমন ListView অবজেক্ট পেতে, আপনাকে Fragment-এর পেরেন্ট অ্যাক্টিভিটি ব্যবহার করে Activity.findViewById()-এ কল করতে হবে। setAdapter()-কে কল করার সময় প্যারেন্ট অ্যাক্টিভিটির Context ব্যবহার করুন। যেমন:

Kotlin

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        ...
        // Gets the ListView from the View list of the parent activity
        activity?.also {
            contactsList = it.findViewById<ListView>(R.id.contact_list_view)
            // Gets a CursorAdapter
            cursorAdapter = SimpleCursorAdapter(
                    it,
                    R.layout.contact_list_item,
                    null,
                    FROM_COLUMNS, TO_IDS,
                    0
            )
            // Sets the adapter for the ListView
            contactsList.adapter = cursorAdapter
        }
    }

জাভা

    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ...
        // Gets the ListView from the View list of the parent activity
        contactsList =
            (ListView) getActivity().findViewById(R.layout.contact_list_view);
        // Gets a CursorAdapter
        cursorAdapter = new SimpleCursorAdapter(
                getActivity(),
                R.layout.contact_list_item,
                null,
                FROM_COLUMNS, TO_IDS,
                0);
        // Sets the adapter for the ListView
        contactsList.setAdapter(cursorAdapter);
    }

বেছে নেওয়া পরিচিতি লিসেনার সেট করুন

আপনি যখন কোনও সার্চের ফলাফল দেখান, তখন সাধারণত ব্যবহারকারীকে আরও প্রসেস করার জন্য একটি সিঙ্গেল পরিচিতি বেছে নিতে দিতে চান। যেমন, ব্যবহারকারী কোনও পরিচিতিতে ক্লিক করলে, আপনি ম্যাপে পরিচিতির ঠিকানা দেখাতে পারেন। এই ফিচার প্রদান করতে, আপনি প্রথমে বর্তমান Fragment-কে ক্লিক লিসনার হিসেবে সংজ্ঞায়িত করেছেন, এর জন্য আপনি উল্লেখ করেছেন যে ক্লাসটি AdapterView.OnItemClickListener প্রয়োগ করে, যেমনটি এমন একটি ফ্র্যাগমেন্ট সংজ্ঞায়িত করুন যা পরিচিতির তালিকা দেখায় বিভাগে দেখানো হয়েছে।

লিসনার সেট-আপ করা চালিয়ে যেতে, onActivityCreated()-এ setOnItemClickListener() পদ্ধতি কল করে ListView-এর সাথে এটি বাইন্ড করুন। যেমন:

Kotlin

    fun onActivityCreated(savedInstanceState:Bundle) {
        ...
        // Set the item click listener to be the current fragment.
        contactsList.onItemClickListener = this
        ...
    }

জাভা

    public void onActivityCreated(Bundle savedInstanceState) {
        ...
        // Set the item click listener to be the current fragment.
        contactsList.setOnItemClickListener(this);
        ...
    }

যেহেতু আপনি নির্দিষ্ট করেছেন যে বর্তমান Fragment হল OnItemClickListener-এর ListView, তাই আপনাকে এখন এর প্রয়োজনীয় পদ্ধতি onItemClick() প্রয়োগ করতে হবে, যা ক্লিক ইভেন্ট ম্যানেজ করে। এটি পরবর্তী বিভাগে বর্ণনা করা হয়েছে।

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

আপনার কোয়েরি থেকে যে কলামগুলি ফেরত পেতে চান সেগুলি সহ একটি কনস্ট্যান্ট নির্ধারণ করুন। ListView-এর মধ্যে থাকা প্রতিটি আইটেম পরিচিতির ডিসপ্লে নাম দেখায়, যেখানে পরিচিতির নামের মূল ফর্ম থাকে। Android 3.0 (API ভার্সন 11) ও এর পরের যেকোনও ভার্সনে, এই কলামের নাম হল Contacts.DISPLAY_NAME_PRIMARY; এর আগের যেকোনও ভার্সনে, এর নাম হল Contacts.DISPLAY_NAME.

Contacts._ID কলামটি SimpleCursorAdapter বাইন্ডিং প্রসেস ব্যবহার করে। Contacts._ID এবং LOOKUP_KEY একসাথে ব্যবহার করে ব্যবহারকারীর বেছে নেওয়া পরিচিতির জন্য কন্টেন্ট URI তৈরি করা হয়।

Kotlin

...
@SuppressLint("InlinedApi")
private val PROJECTION: Array<out String> = arrayOf(
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.LOOKUP_KEY,
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
            ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
        else
            ContactsContract.Contacts.DISPLAY_NAME
)

জাভা

...
@SuppressLint("InlinedApi")
private static final String[] PROJECTION =
        {
            Contacts._ID,
            Contacts.LOOKUP_KEY,
            Build.VERSION.SDK_INT
                    >= Build.VERSION_CODES.HONEYCOMB ?
                    ContactsContract.Contacts.DISPLAY_NAME_PRIMARY :
                    ContactsContract.Contacts.DISPLAY_NAME

        };

কার্সর কলাম ইনডেক্সের জন্য ধ্রুবক সংজ্ঞায়িত করুন

Cursor-এর কোনও একটি কলাম থেকে ডেটা পেতে, আপনাকে Cursor-এর মধ্যে কলামের ইন্ডেক্স জানতে হবে। আপনি Cursor কলামের ইনডেক্সের জন্য ধ্রুবক নির্ধারণ করতে পারবেন, কারণ ইনডেক্সগুলি আপনার প্রজেকশনে কলামের নামের ক্রমের মতোই হয়। যেমন:

Kotlin

// The column index for the _ID column
private const val CONTACT_ID_INDEX: Int = 0
// The column index for the CONTACT_KEY column
private const val CONTACT_KEY_INDEX: Int = 1

জাভা

// The column index for the _ID column
private static final int CONTACT_ID_INDEX = 0;
// The column index for the CONTACT_KEY column
private static final int CONTACT_KEY_INDEX = 1;

বেছে নেওয়ার শর্ত উল্লেখ করুন

আপনি যে ডেটা চান তা নির্দিষ্ট করতে, টেক্সট এক্সপ্রেশন ও ভেরিয়েবলের একটি কম্বিনেশন তৈরি করুন যা প্রদানকারীকে সার্চ করার জন্য ডেটা কলাম ও খুঁজে পাওয়ার জন্য ভ্যালু সম্পর্কে জানায়।

টেক্সট এক্সপ্রেশনের জন্য, একটি কনস্ট্যান্ট নির্ধারণ করুন যা সার্চ কলামের তালিকা দেখায়। যদিও এই এক্সপ্রেশনে ভ্যালুও থাকতে পারে, তবে "?" প্লেসহোল্ডার দিয়ে ভ্যালু দেখানোই হল সবচেয়ে ভালো পদ্ধতি। রিট্রিভ করার সময়, প্লেসহোল্ডারটি একটি অ্যারের ভ্যালু দিয়ে পাল্টে দেওয়া হয়। প্লেসহোল্ডার হিসেবে "?" ব্যবহার করলে এটি নিশ্চিত হয় যে সার্চ স্পেসিফিকেশন SQL কম্পাইলেশনের পরিবর্তে বাইন্ডিংয়ের মাধ্যমে জেনারেট করা হয়েছে। এই পদ্ধতি ক্ষতিকর SQL ইঞ্জেকশনের সম্ভাবনা দূর করে। যেমন:

Kotlin

// Defines the text expression
@SuppressLint("InlinedApi")
private val SELECTION: String =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
            "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE ?"
        else
            "${ContactsContract.Contacts.DISPLAY_NAME} LIKE ?"
...
    // Defines a variable for the search string
    private val searchString: String = ...
    // Defines the array to hold values that replace the ?
    private val selectionArgs = arrayOf<String>(searchString)

জাভা

    // Defines the text expression
    @SuppressLint("InlinedApi")
    private static final String SELECTION =
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
            Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
            Contacts.DISPLAY_NAME + " LIKE ?";
    // Defines a variable for the search string
    private String searchString;
    // Defines the array to hold values that replace the ?
    private String[] selectionArgs = { searchString };

onItemClick() মেথডকে সংজ্ঞায়িত করা

আগের বিভাগে, আপনি ListView-এর জন্য আইটেম ক্লিক লিসনার সেট করেছেন। এখন AdapterView.OnItemClickListener.onItemClick() পদ্ধতিটি সংজ্ঞায়িত করে লিসেনারের জন্য অ্যাকশনটি প্রয়োগ করুন:

Kotlin

    override fun onItemClick(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
        // Get the Cursor
        val cursor: Cursor? = (parent.adapter as? CursorAdapter)?.cursor?.apply {
            // Move to the selected contact
            moveToPosition(position)
            // Get the _ID value
            contactId = getLong(CONTACT_ID_INDEX)
            // Get the selected LOOKUP KEY
            contactKey = getString(CONTACT_KEY_INDEX)
            // Create the contact's content Uri
            contactUri = ContactsContract.Contacts.getLookupUri(contactId, mContactKey)
            /*
             * You can use contactUri as the content URI for retrieving
             * the details for a contact.
             */
        }
    }

জাভা

    @Override
    public void onItemClick(
        AdapterView<?> parent, View item, int position, long rowID) {
        // Get the Cursor
        Cursor cursor = parent.getAdapter().getCursor();
        // Move to the selected contact
        cursor.moveToPosition(position);
        // Get the _ID value
        contactId = cursor.getLong(CONTACT_ID_INDEX);
        // Get the selected LOOKUP KEY
        contactKey = cursor.getString(CONTACT_KEY_INDEX);
        // Create the contact's content Uri
        contactUri = Contacts.getLookupUri(contactId, mContactKey);
        /*
         * You can use contactUri as the content URI for retrieving
         * the details for a contact.
         */
    }

লোডার চালু করুন

যেহেতু আপনি ডেটা ফিরিয়ে আনার জন্য CursorLoader ব্যবহার করছেন, আপনাকে অবশ্যই ব্যাকগ্রাউন্ড থ্রেড এবং অন্যান্য ভেরিয়েবল শুরু করতে হবে যা অ্যাসিঙ্ক্রোনাস ফিরিয়ে আনা নিয়ন্ত্রণ করে। নিচের উদাহরণে দেখানো onCreate() পদ্ধতি অনুসারে ইনিশিয়ালাইজেশন করুন:

Kotlin

class ContactsFragment :
        Fragment(),
        LoaderManager.LoaderCallbacks<Cursor> {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        // Always call the super method first
        super.onCreate(savedInstanceState)
        ...
        // Initializes the loader
        loaderManager.initLoader(0, null, this)

জাভা

public class ContactsFragment extends Fragment implements
        LoaderManager.LoaderCallbacks<Cursor> {
    ...
    // Called just before the Fragment displays its UI
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Always call the super method first
        super.onCreate(savedInstanceState);
        ...
        // Initializes the loader
        getLoaderManager().initLoader(0, null, this);

onCreateLoader() প্রয়োগ করুন

onCreateLoader() পদ্ধতি প্রয়োগ করুন, যা আপনি initLoader() কল করার সাথে সাথেই লোডার ফ্রেমওয়ার্কের মাধ্যমে কল করা হয়।

onCreateLoader()-এ, সার্চ স্ট্রিং প্যাটার্ন সেট-আপ করুন। কোনও স্ট্রিংকে প্যাটার্নে পরিণত করতে, শূন্য বা তার বেশি অক্ষরের ক্রম বোঝাতে "%" (শতাংশ) অক্ষর বা একটি অক্ষর বোঝাতে "_" (আন্ডারস্কোর) অক্ষর বা দুটিই যোগ করুন। যেমন, "%Jefferson%" প্যাটার্নটি "Thomas Jefferson" এবং "Jefferson Davis" দুটির সাথেই মিলবে।

পদ্ধতি থেকে নতুন CursorLoader রিটার্ন করুন। কন্টেন্ট URI-এর জন্য, Contacts.CONTENT_URI ব্যবহার করুন। এই URI সম্পূর্ণ টেবিলকে রেফার করে, যেমন নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

Kotlin

    ...
    override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
        /*
         * Makes search string into pattern and
         * stores it in the selection array
         */
        selectionArgs[0] = "%$mSearchString%"
        // Starts the query
        return activity?.let {
            return CursorLoader(
                    it,
                    ContactsContract.Contacts.CONTENT_URI,
                    PROJECTION,
                    SELECTION,
                    selectionArgs,
                    null
            )
        } ?: throw IllegalStateException()
    }

জাভা

    ...
    @Override
    public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
        /*
         * Makes search string into pattern and
         * stores it in the selection array
         */
        selectionArgs[0] = "%" + searchString + "%";
        // Starts the query
        return new CursorLoader(
                getActivity(),
                ContactsContract.Contacts.CONTENT_URI,
                PROJECTION,
                SELECTION,
                selectionArgs,
                null
        );
    }

onLoadFinished() ও onLoaderReset() প্রয়োগ করা

onLoadFinished() পদ্ধতি প্রয়োগ করুন। পরিচিতি প্রদানকারী কোয়েরির ফলাফল রিটার্ন করলে, লোডার ফ্রেমওয়ার্ক onLoadFinished() কল করে। এই পদ্ধতিতে, SimpleCursorAdapter-এ ফলাফল Cursor রাখুন। এটি সার্চ ফলাফলের সাথে অটোমেটিক ListView আপডেট করে:

Kotlin

    override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
        // Put the result Cursor in the adapter for the ListView
        cursorAdapter?.swapCursor(cursor)
    }

জাভা

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        // Put the result Cursor in the adapter for the ListView
        cursorAdapter.swapCursor(cursor);
    }

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

Kotlin

    override fun onLoaderReset(loader: Loader<Cursor>) {
        // Delete the reference to the existing Cursor
        cursorAdapter?.swapCursor(null)
    }

জাভা

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // Delete the reference to the existing Cursor
        cursorAdapter.swapCursor(null);

    }

আপনার কাছে এখন এমন একটি অ্যাপের মূল অংশ রয়েছে যা পরিচিতির নামের সাথে সার্চ স্ট্রিং ম্যাচ করে এবং ListView-এ ফলাফল দেখায়। ব্যবহারকারী কোনও পরিচিতির নাম বেছে নিতে সেটির উপর ক্লিক করতে পারেন। এটি একটি লিসেনার ট্রিগার করে, যার মাধ্যমে আপনি পরিচিতির ডেটা নিয়ে আরও কাজ করতে পারবেন। যেমন, আপনি পরিচিতির বিবরণ ফিরিয়ে আনতে পারবেন। এটি কীভাবে করবেন তা জানতে, পরবর্তী পাঠ, কোনও পরিচিতির বিবরণ দেখা, চালিয়ে যান।

সার্চ ইউজার ইন্টারফেস সম্পর্কে আরও জানতে, API নির্দেশিকা সার্চ ইন্টারফেস তৈরি করুন পড়ুন।

এই পাঠের বাকি অংশগুলি Contacts Provider-এ পরিচিতি খোঁজার অন্যান্য উপায় দেখায়।

নির্দিষ্ট ধরনের ডেটা দিয়ে পরিচিতি ম্যাচ করা

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

এই ধরনের রিট্রিভাল প্রয়োগ করতে, প্রথমে নিম্নলিখিত কোড প্রয়োগ করুন, যা আগের বিভাগে তালিকাভুক্ত করা হয়েছে:

  • প্রোভাইডার রিড করার জন্য অনুমতি চাওয়া।
  • ListView ও আইটেম লেআউট নির্ধারণ করুন।
  • পরিচিতির তালিকা দেখায় এমন একটি ফ্র্যাগমেন্ট নির্ধারণ করুন।
  • গ্লোবাল ভেরিয়েবেল সংজ্ঞায়িত করো।
  • ফ্র্যাগমেন্ট শুরু করুন।
  • ListView-এর জন্য CursorAdapter সেট-আপ করুন।
  • বেছে নেওয়া পরিচিতি লিসেনার সেট করুন।
  • কার্সর কলাম ইনডেক্সের জন্য ধ্রুবক নির্ধারণ করুন।

    আপনি অন্য টেবিল থেকে ডেটা রিট্রিভ করলেও, প্রজেকশনের কলামের ক্রম একই থাকে, তাই আপনি Cursor-এর জন্য একই ইন্ডেক্স ব্যবহার করতে পারবেন।

  • onItemClick() মেথডকে সংজ্ঞায়িত করুন।
  • লোডার চালু করুন।
  • onLoadFinished() ও onLoaderReset() প্রয়োগ করুন।

নিচের ধাপগুলি থেকে আপনি অতিরিক্ত কোড সম্পর্কে জানতে পারবেন যা আপনাকে নির্দিষ্ট ধরনের বিস্তারিত ডেটার সাথে সার্চ স্ট্রিং ম্যাচ করতে এবং ফলাফল দেখাতে হবে।

ডেটার ধরন ও টেবিল বেছে নিন

নির্দিষ্ট ধরনের বিস্তারিত ডেটা সার্চ করতে, আপনাকে ডেটার ধরনের জন্য কাস্টম MIME টাইপের ভ্যালু জানতে হবে। প্রতিটি ডেটার ধরনের একটি অনন্য MIME-এর প্রকার মান আছে যা ডেটার ধরনের সাথে যুক্ত ContactsContract.CommonDataKinds-এর সাবক্লাসে CONTENT_ITEM_TYPE কনস্ট্যান্ট দ্বারা সংজ্ঞায়িত করা হয়। সাবক্লাসের নামে ডেটার ধরন উল্লেখ করা থাকে; যেমন, ইমেল ডেটার সাবক্লাস হল ContactsContract.CommonDataKinds.Email এবং ইমেল ডেটার কাস্টম MIME টাইপকে ধ্রুবক Email.CONTENT_ITEM_TYPE দ্বারা সংজ্ঞায়িত করা হয়।

আপনার সার্চের জন্য ContactsContract.Data টেবিল ব্যবহার করুন। আপনার প্রজেকশন, সিলেকশন ক্লজ ও সর্ট অর্ডারের জন্য প্রয়োজনীয় সব কনস্ট্যান্ট এই টেবিলে ডিফাইন করা আছে বা এই টেবিল থেকে ইনহেরিট করা হয়েছে।

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

প্রোজেকশন নির্ধারণ করতে, ContactsContract.Data-এ নির্ধারিত এক বা একাধিক কলাম অথবা যে ক্লাস থেকে এটি ইনহেরিট করে তা বেছে নিন। Contacts Provider সারি দেখানোর আগে ContactsContract.Data ও অন্যান্য টেবিলের মধ্যে ইমপ্লিসিট জয়েন করে। যেমন:

Kotlin

@SuppressLint("InlinedApi")
private val PROJECTION: Array<out String> = arrayOf(
        /*
         * The detail data row ID. To make a ListView work,
         * this column is required.
         */
        ContactsContract.Data._ID,
        // The primary display name
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
            ContactsContract.Data.DISPLAY_NAME_PRIMARY
        else
            ContactsContract.Data.DISPLAY_NAME,
        // The contact's _ID, to construct a content URI
        ContactsContract.Data.CONTACT_ID,
        // The contact's LOOKUP_KEY, to construct a content URI
        ContactsContract.Data.LOOKUP_KEY
)

জাভা

    @SuppressLint("InlinedApi")
    private static final String[] PROJECTION =
        {
            /*
             * The detail data row ID. To make a ListView work,
             * this column is required.
             */
            ContactsContract.Data._ID,
            // The primary display name
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
                    ContactsContract.Data.DISPLAY_NAME_PRIMARY :
                    ContactsContract.Data.DISPLAY_NAME,
            // The contact's _ID, to construct a content URI
            ContactsContract.Data.CONTACT_ID,
            // The contact's LOOKUP_KEY, to construct a content URI
            ContactsContract.Data.LOOKUP_KEY // A permanent link to the contact
        };

সার্চের শর্ত নির্ধারণ করা

নির্দিষ্ট ধরনের ডেটার মধ্যে স্ট্রিং খুঁজতে, নিম্নলিখিত থেকে একটি সিলেকশন ক্লজ তৈরি করুন:

  • আপনার সার্চ স্ট্রিং রয়েছে এমন কলামের নাম। ডেটার ধরন অনুযায়ী এই নাম আলাদা হয়, তাই আপনাকে ContactsContract.CommonDataKinds-এর সেই সাবক্লাস খুঁজে বের করতে হবে যা ডেটার ধরনের সাথে সম্পর্কিত এবং তারপরে সেই সাবক্লাস থেকে কলামের নাম বেছে নিতে হবে। যেমন, ইমেল আইডি সার্চ করতে, কলাম Email.ADDRESS ব্যবহার করুন।
  • সার্চ স্ট্রিং নিজেই, সিলেকশন ক্লজে "?" অক্ষর হিসেবে দেখানো হয়েছে।
  • কাস্টম MIME-এর প্রকারের মান সহ কলামের নাম। এই নাম সবসময় Data.MIMETYPE হয়।
  • ডেটার ধরনের জন্য কাস্টম MIME ধরনের ভ্যালু। আগে যেমন বর্ণনা করা হয়েছে, এটি হল ContactsContract.CommonDataKinds সাবক্লাসের CONTENT_ITEM_TYPE কনস্ট্যান্ট। যেমন, ইমেল ডেটার জন্য MIME টাইপের ভ্যালু হল Email.CONTENT_ITEM_TYPE। কনস্ট্যান্টের শুরু ও শেষে "'" (সিঙ্গেল কোট) অক্ষর যোগ করে সিঙ্গেল কোটের মধ্যে ভ্যালু লিখুন; অন্যথায়, প্রোভাইডার ভ্যালুটিকে স্ট্রিং ভ্যালু হিসেবে না দেখে ভেরিয়েবল নাম হিসেবে দেখবে। এই ভ্যালুর জন্য আপনাকে প্লেসহোল্ডার ব্যবহার করতে হবে না, কারণ আপনি ব্যবহারকারীর দেওয়া ভ্যালুর পরিবর্তে একটি কনস্ট্যান্ট ব্যবহার করছেন।

যেমন:

Kotlin

/*
 * Constructs search criteria from the search string
 * and email MIME type
 */
private val SELECTION: String =
        /*
         * Searches for an email address
         * that matches the search string
         */
        "${Email.ADDRESS} LIKE ? AND " +
        /*
         * Searches for a MIME type that matches
         * the value of the constant
         * Email.CONTENT_ITEM_TYPE. Note the
         * single quotes surrounding Email.CONTENT_ITEM_TYPE.
         */
        "${ContactsContract.Data.MIMETYPE } = '${Email.CONTENT_ITEM_TYPE}'"

জাভা

    /*
     * Constructs search criteria from the search string
     * and email MIME type
     */
    private static final String SELECTION =
            /*
             * Searches for an email address
             * that matches the search string
             */
            Email.ADDRESS + " LIKE ? " + "AND " +
            /*
             * Searches for a MIME type that matches
             * the value of the constant
             * Email.CONTENT_ITEM_TYPE. Note the
             * single quotes surrounding Email.CONTENT_ITEM_TYPE.
             */
            ContactsContract.Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";

এরপর, বেছে নেওয়া আর্গুমেন্ট ধারণ করার জন্য ভেরিয়েবল নির্ধারণ করুন:

Kotlin

    private var searchString: String? = null
    private val selectionArgs: Array<String> = arrayOf("")

জাভা

    String searchString;
    String[] selectionArgs = { "" };

onCreateLoader() প্রয়োগ করুন

আপনি যে ডেটা চান এবং কীভাবে তা খুঁজে পাবেন তা নির্দিষ্ট করেছেন, এখন আপনার onCreateLoader()-এর ইমপ্লিমেন্টেশনে একটি কোয়েরি নির্ধারণ করুন। আপনার প্রোজেকশন, বেছে নেওয়া টেক্সট এক্সপ্রেশন এবং বেছে নেওয়া অ্যারে আর্গুমেন্ট হিসেবে ব্যবহার করে, এই পদ্ধতি থেকে নতুন CursorLoader রিটার্ন করুন। কন্টেন্ট URI-এর জন্য, Data.CONTENT_URI ব্যবহার করুন। যেমন:

Kotlin

    override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
        // OPTIONAL: Makes search string into pattern
        searchString = "%$mSearchString%"

        searchString?.also {
            // Puts the search string into the selection criteria
            selectionArgs[0] = it
        }
        // Starts the query
        return activity?.let {
            CursorLoader(
                    it,
                    ContactsContract.Data.CONTENT_URI,
                    PROJECTION,
                    SELECTION,
                    selectionArgs,
                    null
            )
        } ?: throw IllegalStateException()
    }

জাভা

@Override
    public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
        // OPTIONAL: Makes search string into pattern
        searchString = "%" + searchString + "%";
        // Puts the search string into the selection criteria
        selectionArgs[0] = searchString;
        // Starts the query
        return new CursorLoader(
                getActivity(),
                Data.CONTENT_URI,
                PROJECTION,
                SELECTION,
                selectionArgs,
                null
        );
    }

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

যেকোনও ধরনের ডেটা দিয়ে পরিচিতি ম্যাচ করুন

যেকোনও ধরনের ডেটার উপর ভিত্তি করে কোনও পরিচিতি ফিরিয়ে আনার সময়, যদি তার কোনও ডেটা সার্চ স্ট্রিংয়ের সাথে মিলে যায়, তাহলে পরিচিতি ফিরিয়ে আনা হয়, এর মধ্যে নাম, ইমেল আইডি, পোস্টাল অ্যাড্রেস, ফোন নম্বর এবং আরও অনেক কিছু অন্তর্ভুক্ত। এর ফলে সার্চ ফলাফলের একটি বিস্তৃত সেট পাওয়া যায়। যেমন, সার্চ স্ট্রিং "Doe" হলে, যেকোনও ডেটা টাইপ সার্চ করলে "John Doe" পরিচিতিটি পাওয়া যায়; এছাড়াও, "Doe Street"-এ বসবাসকারী পরিচিতিও পাওয়া যায়।

এই ধরনের রিট্রিভাল প্রয়োগ করতে, প্রথমে নিম্নলিখিত কোড প্রয়োগ করুন, যেমনটি আগের বিভাগে তালিকাভুক্ত করা হয়েছে:

  • প্রোভাইডার রিড করার জন্য অনুমতি চাওয়া।
  • ListView ও আইটেম লেআউট নির্ধারণ করুন।
  • পরিচিতির তালিকা দেখায় এমন একটি ফ্র্যাগমেন্ট নির্ধারণ করুন।
  • গ্লোবাল ভেরিয়েবেল সংজ্ঞায়িত করো।
  • ফ্র্যাগমেন্ট শুরু করুন।
  • ListView-এর জন্য CursorAdapter সেট-আপ করুন।
  • বেছে নেওয়া পরিচিতি লিসেনার সেট করুন।
  • প্রোজেকশন নির্দিষ্ট করুন।
  • কার্সর কলাম ইনডেক্সের জন্য ধ্রুবক নির্ধারণ করুন।

    এই ধরনের রিট্রিভালের জন্য, আপনি সেই একই টেবিল ব্যবহার করছেন যা আপনি নামের মাধ্যমে পরিচিতি ম্যাচ করুন এবং ফলাফল তালিকাভুক্ত করুন বিভাগে ব্যবহার করেছেন। একই কলাম ইনডেক্স ব্যবহার করুন।

  • onItemClick() পদ্ধতিটি সংজ্ঞায়িত করুন।
  • লোডার চালু করুন।
  • onLoadFinished() এবং onLoaderReset() প্রয়োগ করুন।

নিম্নলিখিত ধাপগুলি থেকে আপনি জানতে পারবেন যে যেকোনও ধরনের ডেটার সাথে সার্চ স্ট্রিং ম্যাচ করতে এবং ফলাফল দেখাতে আপনাকে কোন অতিরিক্ত কোড ব্যবহার করতে হবে।

বেছে নেওয়ার শর্ত সরিয়ে দিন

SELECTION ধ্রুবক বা mSelectionArgs ভেরিয়েবেলকে সংজ্ঞায়িত করবেন না। এই ধরনের রিট্রিভালে এগুলি ব্যবহার করা হয় না।

onCreateLoader() প্রয়োগ করুন

onCreateLoader() পদ্ধতি প্রয়োগ করুন, নতুন CursorLoader রিটার্ন করুন। আপনাকে সার্চ স্ট্রিং কোনও প্যাটার্নে কনভার্ট করতে হবে না, কারণ কন্ট্যাক্ট প্রোভাইডার সেটি অটোমেটিক করে দেয়। বেস URI হিসেবে Contacts.CONTENT_FILTER_URI ব্যবহার করুন এবং Uri.withAppendedPath() কল করে আপনার সার্চ স্ট্রিং এতে যোগ করুন। এই URI ব্যবহার করলে নিম্নলিখিত উদাহরণে দেখানো ডেটার যেকোনও ধরন অটোমেটিক সার্চ করা হয়:

Kotlin

    override fun onCreateLoader(loaderId: Int, args: Bundle?): Loader<Cursor> {
        /*
         * Appends the search string to the base URI. Always
         * encode search strings to ensure they're in proper
         * format.
         */
        val contentUri: Uri = Uri.withAppendedPath(
                ContactsContract.Contacts.CONTENT_FILTER_URI,
                Uri.encode(searchString)
        )
        // Starts the query
        return activity?.let {
            CursorLoader(
                    it,
                    contentUri,
                    PROJECTION2,
                    null,
                    null,
                    null
            )
        } ?: throw IllegalStateException()
    }

জাভা

    @Override
    public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
        /*
         * Appends the search string to the base URI. Always
         * encode search strings to ensure they're in proper
         * format.
         */
        Uri contentUri = Uri.withAppendedPath(
                Contacts.CONTENT_FILTER_URI,
                Uri.encode(searchString));
        // Starts the query
        return new CursorLoader(
                getActivity(),
                contentUri,
                PROJECTION,
                null,
                null,
                null
        );
    }

এই কোড স্নিপেটগুলি এমন একটি অ্যাপের ভিত্তি যা পরিচিতি প্রদানকারীর একটি বিস্তৃত সার্চ করে। এই টেকনিকটি সেইসব অ্যাপের জন্য উপযোগী যেগুলি 'পরিচিতি' অ্যাপের পরিচিতি তালিকা স্ক্রিনের মতো কার্যকারিতা প্রয়োগ করতে চায়।