একটি ক্যাটালগ ব্রাউজার তৈরি করুন

কম্পোজ দিয়ে আরও ভালোভাবে তৈরি করুন
জেটপ্যাক কম্পোজ ব্যবহার করে অ্যান্ড্রয়েড টিভি ওএস-এর জন্য ন্যূনতম কোডে সুন্দর ইউআই তৈরি করুন।

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

এই নির্দেশিকায় আলোচনা করা হয়েছে কিভাবে অপ্রচলিত androidx.leanback লাইব্রেরির ক্লাসগুলো ব্যবহার করে আপনার অ্যাপের মিডিয়া ক্যাটালগ থেকে গান বা ভিডিও ব্রাউজ করার জন্য একটি ইউজার ইন্টারফেস তৈরি করা যায়।

দ্রষ্টব্য: এখানে দেখানো বাস্তবায়ন উদাহরণটিতে অপ্রচলিত BrowseFragment ক্লাসের পরিবর্তে BrowseSupportFragment ব্যবহার করা হয়েছে। BrowseSupportFragment AndroidX Fragment ক্লাসকে এক্সটেন্ড করে, যা বিভিন্ন ডিভাইস এবং অ্যান্ড্রয়েড সংস্করণে সামঞ্জস্যপূর্ণ আচরণ নিশ্চিত করতে সাহায্য করে।

অ্যাপের প্রধান স্ক্রিন

চিত্র ১. লিনব্যাক স্যাম্পল অ্যাপের ব্রাউজ ফ্র্যাগমেন্টটি ভিডিও ক্যাটালগের ডেটা প্রদর্শন করে।

একটি মিডিয়া ব্রাউজ লেআউট তৈরি করুন

Leanback UI টুলকিটের BrowseSupportFragment ক্লাসটি আপনাকে খুব অল্প কোড ব্যবহার করে মিডিয়া আইটেমের ক্যাটাগরি ও সারি ব্রাউজ করার জন্য একটি প্রাথমিক লেআউট তৈরি করতে দেয়। নিচের উদাহরণটিতে দেখানো হয়েছে কিভাবে একটি BrowseSupportFragment অবজেক্ট সম্বলিত লেআউট তৈরি করতে হয়:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:name="com.example.android.tvleanback.ui.MainFragment"
        android:id="@+id/main_browse_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

অ্যাপ্লিকেশনটির প্রধান অ্যাক্টিভিটি এই ভিউটি সেট করে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

class MainActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }
...

জাভা

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
...

BrowseSupportFragment মেথডগুলো ভিডিও ডেটা ও UI এলিমেন্ট দিয়ে ভিউটি পূরণ করে এবং আইকন ও টাইটেলের মতো লেআউট প্যারামিটার সেট করে, সেইসাথে ক্যাটাগরি হেডারগুলো সক্রিয় থাকবে কিনা তাও নির্ধারণ করে।

UI এলিমেন্ট সেট আপ করার বিষয়ে আরও তথ্যের জন্য, ‘UI এলিমেন্ট সেট করুন’ বিভাগটি দেখুন। হেডার লুকানোর বিষয়ে আরও তথ্যের জন্য, ‘হেডার লুকান বা নিষ্ক্রিয় করুন’ বিভাগটি দেখুন।

অ্যাপ্লিকেশনটির যে সাবক্লাসটি BrowseSupportFragment মেথডগুলো ইমপ্লিমেন্ট করে, সেটি UI এলিমেন্টগুলোর উপর ব্যবহারকারীর কার্যকলাপের জন্য ইভেন্ট লিসেনারও সেট আপ করে এবং ব্যাকগ্রাউন্ড ম্যানেজারকে প্রস্তুত করে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

class MainFragment : BrowseSupportFragment(),
        LoaderManager.LoaderCallbacks<HashMap<String, List<Movie>>> {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        loadVideoData()
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        prepareBackgroundManager()
        setupUIElements()
        setupEventListeners()
    }
    ...
    private fun prepareBackgroundManager() {
        backgroundManager = BackgroundManager.getInstance(activity).apply {
            attach(activity?.window)
        }
        defaultBackground = resources.getDrawable(R.drawable.default_background)
        metrics = DisplayMetrics()
        activity?.windowManager?.defaultDisplay?.getMetrics(metrics)
    }

    private fun setupUIElements() {
        badgeDrawable = resources.getDrawable(R.drawable.videos_by_google_banner)
        // Badge, when set, takes precedent over title
        title = getString(R.string.browse_title)
        headersState = BrowseSupportFragment.HEADERS_ENABLED
        isHeadersTransitionOnBackEnabled = true
        // Set header background color
        brandColor = ContextCompat.getColor(requireContext(), R.color.fastlane_background)

        // Set search icon color
        searchAffordanceColor = ContextCompat.getColor(requireContext(), R.color.search_opaque)
    }

    private fun loadVideoData() {
        VideoProvider.setContext(activity)
        videosUrl = getString(R.string.catalog_url)
        loaderManager.initLoader(0, null, this)
    }

    private fun setupEventListeners() {
        setOnSearchClickedListener {
            Intent(activity, SearchActivity::class.java).also { intent ->
                startActivity(intent)
            }
        }

        onItemViewClickedListener = ItemViewClickedListener()
        onItemViewSelectedListener = ItemViewSelectedListener()
    }
    ...

জাভা

public class MainFragment extends BrowseSupportFragment implements
        LoaderManager.LoaderCallbacks<HashMap<String, List<Movie>>> {
}
...
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        loadVideoData();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        prepareBackgroundManager();
        setupUIElements();
        setupEventListeners();
    }
...
    private void prepareBackgroundManager() {
        backgroundManager = BackgroundManager.getInstance(getActivity());
        backgroundManager.attach(getActivity().getWindow());
        defaultBackground = getResources()
            .getDrawable(R.drawable.default_background);
        metrics = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
    }

    private void setupUIElements() {
        setBadgeDrawable(getActivity().getResources()
            .getDrawable(R.drawable.videos_by_google_banner));
        // Badge, when set, takes precedent over title
        setTitle(getString(R.string.browse_title));
        setHeadersState(HEADERS_ENABLED);
        setHeadersTransitionOnBackEnabled(true);
        // Set header background color
        setBrandColor(ContextCompat.getColor(requireContext(), R.color.fastlane_background));
        // Set search icon color
        setSearchAffordanceColor(ContextCompat.getColor(requireContext(), R.color.search_opaque));
    }

    private void loadVideoData() {
        VideoProvider.setContext(getActivity());
        videosUrl = getString(R.string.catalog_url);
        getLoaderManager().initLoader(0, null, this);
    }

    private void setupEventListeners() {
        setOnSearchClickedListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Intent intent = new Intent(getActivity(), SearchActivity.class);
                startActivity(intent);
            }
        });

        setOnItemViewClickedListener(new ItemViewClickedListener());
        setOnItemViewSelectedListener(new ItemViewSelectedListener());
    }
...

UI উপাদান সেট করুন

পূর্ববর্তী নমুনায়, private method setupUIElements() মিডিয়া ক্যাটালগ ব্রাউজারকে স্টাইল করার জন্য BrowseSupportFragment বেশ কয়েকটি মেথডকে কল করে:

  • setBadgeDrawable() নির্দিষ্ট ড্রয়েবল রিসোর্সটিকে ব্রাউজ ফ্র্যাগমেন্টের উপরের-ডান কোণায় স্থাপন করে, যেমনটি চিত্র ১ এবং ২-এ দেখানো হয়েছে। যদি setTitle() মেথডটিও কল করা হয়, তবে এই মেথডটি টাইটেল স্ট্রিং-কে ড্রয়েবল রিসোর্স দিয়ে প্রতিস্থাপন করে। ড্রয়েবল রিসোর্সটির উচ্চতা অবশ্যই ৫২ ডিপি হতে হবে।
  • setBadgeDrawable() কল করা না হলে, setTitle() ব্রাউজ ফ্র্যাগমেন্টের উপরের-ডান কোণায় টাইটেল স্ট্রিংটি সেট করে।
  • setHeadersState() এবং setHeadersTransitionOnBackEnabled() হেডারগুলো লুকায় বা নিষ্ক্রিয় করে। আরও তথ্যের জন্য "হেডার লুকান বা নিষ্ক্রিয় করুন" অংশটি দেখুন।
  • setBrandColor() ফাংশনটি ব্রাউজ ফ্র্যাগমেন্টের UI এলিমেন্টগুলোর, বিশেষ করে হেডার সেকশনের, ব্যাকগ্রাউন্ড কালার নির্দিষ্ট কালার ভ্যালু দিয়ে সেট করে।
  • setSearchAffordanceColor() নির্দিষ্ট রঙের মান দিয়ে সার্চ আইকনের রঙ নির্ধারণ করে। সার্চ আইকনটি ব্রাউজ ফ্র্যাগমেন্টের উপরের-বাম কোণে প্রদর্শিত হয়, যেমনটি চিত্র ১ এবং ২-এ দেখানো হয়েছে।

হেডার ভিউগুলি কাস্টমাইজ করুন

চিত্র ১-এ দেখানো ব্রাউজ ফ্র্যাগমেন্টটি ভিডিও ক্যাটাগরির নামগুলো, যা ভিডিও ডেটাবেসের সারি হেডার, টেক্সট ভিউতে প্রদর্শন করে। আরও জটিল লেআউটে অতিরিক্ত ভিউ অন্তর্ভুক্ত করার জন্য আপনি হেডারটি কাস্টমাইজও করতে পারেন। পরবর্তী বিভাগগুলোতে দেখানো হয়েছে কীভাবে একটি ইমেজ ভিউ অন্তর্ভুক্ত করতে হয়, যা চিত্র ২-এর মতো ক্যাটাগরির নামের পাশে একটি আইকন প্রদর্শন করে।

অ্যাপের প্রধান স্ক্রিন

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

সারি শিরোনামের বিন্যাসটি নিম্নরূপভাবে সংজ্ঞায়িত করা হয়েছে:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/header_icon"
        android:layout_width="32dp"
        android:layout_height="32dp" />
    <TextView
        android:id="@+id/header_label"
        android:layout_marginTop="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

একটি Presenter ব্যবহার করুন এবং ভিউ হোল্ডার তৈরি, বাইন্ড ও আনবাইন্ড করার জন্য অ্যাবস্ট্রাক্ট মেথডগুলো ইমপ্লিমেন্ট করুন। নিচের উদাহরণটিতে দেখানো হয়েছে কিভাবে একটি ভিউহোল্ডারকে দুটি ভিউ—একটি ImageView এবং একটি TextView এর সাথে বাইন্ড করতে হয়।

কোটলিন

class IconHeaderItemPresenter : Presenter() {

    override fun onCreateViewHolder(viewGroup: ViewGroup): Presenter.ViewHolder {
        val view = LayoutInflater.from(viewGroup.context).run {
            inflate(R.layout.icon_header_item, null)
        }

        return Presenter.ViewHolder(view)
    }


    override fun onBindViewHolder(viewHolder: Presenter.ViewHolder, o: Any) {
        val headerItem = (o as ListRow).headerItem
        val rootView = viewHolder.view

        rootView.findViewById<ImageView>(R.id.header_icon).apply {
            rootView.resources.getDrawable(R.drawable.ic_action_video, null).also { icon ->
                setImageDrawable(icon)
            }
        }

        rootView.findViewById<TextView>(R.id.header_label).apply {
            text = headerItem.name
        }
    }

    override fun onUnbindViewHolder(viewHolder: Presenter.ViewHolder) {
        // no-op
    }
}

জাভা

public class IconHeaderItemPresenter extends Presenter {
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup) {
        LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());

        View view = inflater.inflate(R.layout.icon_header_item, null);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, Object o) {
        HeaderItem headerItem = ((ListRow) o).getHeaderItem();
        View rootView = viewHolder.view;

        ImageView iconView = (ImageView) rootView.findViewById(R.id.header_icon);
        Drawable icon = rootView.getResources().getDrawable(R.drawable.ic_action_video, null);
        iconView.setImageDrawable(icon);

        TextView label = (TextView) rootView.findViewById(R.id.header_label);
        label.setText(headerItem.getName());
    }

    @Override
    public void onUnbindViewHolder(ViewHolder viewHolder) {
    // no-op
    }
}

আপনার হেডারগুলো ফোকাসযোগ্য হতে হবে, যাতে ডি-প্যাড ব্যবহার করে সেগুলোর মধ্যে স্ক্রল করা যায়। এটি করার দুটি উপায় আছে:

  • onBindViewHolder() -এ আপনার ভিউকে ফোকাসযোগ্য করুন:

    কোটলিন

    override fun onBindViewHolder(viewHolder: Presenter.ViewHolder, o: Any) {
        val headerItem = (o as ListRow).headerItem
        val rootView = viewHolder.view
    
        rootView.focusable = View.FOCUSABLE
        // ...
    }

    জাভা

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, Object o) {
        HeaderItem headerItem = ((ListRow) o).getHeaderItem();
        View rootView = viewHolder.view;
        rootView.setFocusable(View.FOCUSABLE) // Allows the D-Pad to navigate to this header item
        // ...
    }
  • আপনার লেআউটকে ফোকাসযোগ্য করে সেট করুন:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       ...
       android:focusable="true">

অবশেষে, ক্যাটালগ ব্রাউজার প্রদর্শনকারী BrowseSupportFragment ইমপ্লিমেন্টেশনে, নিম্নলিখিত উদাহরণে দেখানো অনুযায়ী, রো হেডারের জন্য প্রেজেন্টার সেট করতে setHeaderPresenterSelector() মেথডটি ব্যবহার করুন।

কোটলিন

setHeaderPresenterSelector(object : PresenterSelector() {
    override fun getPresenter(o: Any): Presenter {
        return IconHeaderItemPresenter()
    }
})

জাভা

setHeaderPresenterSelector(new PresenterSelector() {
    @Override
    public Presenter getPresenter(Object o) {
        return new IconHeaderItemPresenter();
    }
});

একটি সম্পূর্ণ উদাহরণের জন্য, লিনব্যাক স্যাম্পল অ্যাপটি দেখুন।

হেডার লুকান বা নিষ্ক্রিয় করুন

কখনও কখনও আপনি চান না যে সারি হেডারগুলো প্রদর্শিত হোক, যেমন যখন একটি স্ক্রোলযোগ্য তালিকার জন্য যথেষ্ট ক্যাটাগরি থাকে না। সারি হেডারগুলো লুকানোর বা নিষ্ক্রিয় করার জন্য, ফ্র্যাগমেন্টের onActivityCreated() মেথডের সময় BrowseSupportFragment.setHeadersState() মেথডটি কল করুন। setHeadersState() মেথডটি ব্রাউজ ফ্র্যাগমেন্টের হেডারগুলোর প্রাথমিক অবস্থা নির্ধারণ করে, যেখানে প্যারামিটার হিসেবে নিম্নলিখিত কনস্ট্যান্টগুলোর মধ্যে একটি গ্রহণ করা হয়:

  • HEADERS_ENABLED : যখন ব্রাউজ ফ্র্যাগমেন্ট অ্যাক্টিভিটি তৈরি করা হয়, তখন হেডারগুলো ডিফল্টরূপে সক্রিয় এবং প্রদর্শিত হয়। হেডারগুলো এই পৃষ্ঠার চিত্র ১ এবং ২-এ দেখানো অনুযায়ী প্রদর্শিত হয়।
  • HEADERS_HIDDEN : যখন ব্রাউজ ফ্র্যাগমেন্ট অ্যাক্টিভিটি তৈরি করা হয়, তখন হেডারগুলো ডিফল্টরূপে সক্রিয় এবং লুকানো থাকে। স্ক্রিনের হেডার অংশটি সংকুচিত থাকে, যেমনটি 'একটি কার্ড ভিউ প্রদান করুন' অংশের একটি চিত্রে দেখানো হয়েছে। ব্যবহারকারী সংকুচিত হেডার অংশটি নির্বাচন করে এটিকে প্রসারিত করতে পারেন।
  • HEADERS_DISABLED : যখন ব্রাউজ ফ্র্যাগমেন্ট অ্যাক্টিভিটি তৈরি করা হয়, তখন হেডারগুলো ডিফল্টরূপে নিষ্ক্রিয় থাকে এবং কখনোই প্রদর্শিত হয় না।

যদি HEADERS_ENABLED অথবা HEADERS_HIDDEN সেট করা থাকে, তাহলে সারির কোনো নির্বাচিত কন্টেন্ট আইটেম থেকে সারির হেডারে ফিরে যাওয়ার জন্য আপনি setHeadersTransitionOnBackEnabled() কল করতে পারেন। আপনি যদি এই মেথডটি কল না করেন, তবে এটি ডিফল্টরূপে সক্রিয় থাকে। নিজে থেকে ফিরে যাওয়ার বিষয়টি পরিচালনা করতে, setHeadersTransitionOnBackEnabled() -এ false পাস করুন এবং আপনার নিজস্ব ব্যাক স্ট্যাক হ্যান্ডলিং ইমপ্লিমেন্ট করুন।

মিডিয়া তালিকা প্রদর্শন করুন

BrowseSupportFragment ক্লাসটি আপনাকে অ্যাডাপ্টার এবং প্রেজেন্টার ব্যবহার করে একটি মিডিয়া ক্যাটালগ থেকে ব্রাউজযোগ্য মিডিয়া কন্টেন্ট ক্যাটাগরি এবং মিডিয়া আইটেম সংজ্ঞায়িত ও প্রদর্শন করতে দেয়। অ্যাডাপ্টার আপনাকে স্থানীয় বা অনলাইন ডেটা সোর্সের সাথে সংযোগ স্থাপন করতে দেয়, যেগুলোতে আপনার মিডিয়া ক্যাটালগের তথ্য থাকে। স্ক্রিনে কোনো আইটেম প্রদর্শনের জন্য অ্যাডাপ্টারগুলো প্রেজেন্টার ব্যবহার করে ভিউ তৈরি করে এবং সেই ভিউগুলোতে ডেটা বাইন্ড করে।

নিম্নলিখিত উদাহরণ কোডটিতে স্ট্রিং ডেটা প্রদর্শনের জন্য একটি Presenter বাস্তবায়ন দেখানো হয়েছে:

কোটলিন

private const val TAG = "StringPresenter"

class StringPresenter : Presenter() {

    override fun onCreateViewHolder(parent: ViewGroup): Presenter.ViewHolder {
        val textView = TextView(parent.context).apply {
            isFocusable = true
            isFocusableInTouchMode = true
            background = parent.resources.getDrawable(R.drawable.text_bg)
        }
        return Presenter.ViewHolder(textView)
    }

    override fun onBindViewHolder(viewHolder: Presenter.ViewHolder, item: Any) {
        (viewHolder.view as TextView).text = item.toString()
    }

    override fun onUnbindViewHolder(viewHolder: Presenter.ViewHolder) {
        // no op
    }
}

জাভা

public class StringPresenter extends Presenter {
    private static final String TAG = "StringPresenter";

    public ViewHolder onCreateViewHolder(ViewGroup parent) {
        TextView textView = new TextView(parent.getContext());
        textView.setFocusable(true);
        textView.setFocusableInTouchMode(true);
        textView.setBackground(
                parent.getResources().getDrawable(R.drawable.text_bg));
        return new ViewHolder(textView);
    }

    public void onBindViewHolder(ViewHolder viewHolder, Object item) {
        ((TextView) viewHolder.view).setText(item.toString());
    }

    public void onUnbindViewHolder(ViewHolder viewHolder) {
        // no op
    }
}

আপনার মিডিয়া আইটেমগুলির জন্য একবার একটি প্রেজেন্টার ক্লাস তৈরি করে ফেললে, আপনি একটি অ্যাডাপ্টার তৈরি করে সেটিকে BrowseSupportFragment এর সাথে সংযুক্ত করতে পারেন, যাতে ব্যবহারকারী ব্রাউজ করার জন্য সেই আইটেমগুলি স্ক্রিনে প্রদর্শন করতে পারেন। পূর্ববর্তী কোড উদাহরণে দেখানো StringPresenter ক্লাসটি ব্যবহার করে কীভাবে বিভিন্ন ক্যাটাগরি এবং সেই ক্যাটাগরিগুলির আইটেমগুলি প্রদর্শন করার জন্য একটি অ্যাডাপ্টার তৈরি করতে হয়, তা নিম্নলিখিত উদাহরণ কোডটিতে দেখানো হয়েছে:

কোটলিন

private const val NUM_ROWS = 4
...
private lateinit var rowsAdapter: ArrayObjectAdapter

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    buildRowsAdapter()
}

private fun buildRowsAdapter() {
    rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
    for (i in 0 until NUM_ROWS) {
        val listRowAdapter = ArrayObjectAdapter(StringPresenter()).apply {
            add("Media Item 1")
            add("Media Item 2")
            add("Media Item 3")
        }
        HeaderItem(i.toLong(), "Category $i").also { header ->
            rowsAdapter.add(ListRow(header, listRowAdapter))
        }
    }
    browseSupportFragment.adapter = rowsAdapter
}

জাভা

private ArrayObjectAdapter rowsAdapter;
private static final int NUM_ROWS = 4;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    buildRowsAdapter();
}

private void buildRowsAdapter() {
    rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());

    for (int i = 0; i < NUM_ROWS; ++i) {
        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(
                new StringPresenter());
        listRowAdapter.add("Media Item 1");
        listRowAdapter.add("Media Item 2");
        listRowAdapter.add("Media Item 3");
        HeaderItem header = new HeaderItem(i, "Category " + i);
        rowsAdapter.add(new ListRow(header, listRowAdapter));
    }

    browseSupportFragment.setAdapter(rowsAdapter);
}

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

পটভূমি আপডেট করুন

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

Leanback UI টুলকিট আপনার টিভি অ্যাপ অ্যাক্টিভিটির ব্যাকগ্রাউন্ড পরিবর্তন করার জন্য একটি BackgroundManager ক্লাস প্রদান করে। নিম্নলিখিত উদাহরণটি দেখায় কিভাবে আপনার টিভি অ্যাপ অ্যাক্টিভিটির মধ্যে ব্যাকগ্রাউন্ড আপডেট করার জন্য একটি সহজ মেথড তৈরি করতে হয়:

কোটলিন

protected fun updateBackground(drawable: Drawable) {
    BackgroundManager.getInstance(this).drawable = drawable
}

জাভা

protected void updateBackground(Drawable drawable) {
    BackgroundManager.getInstance(this).setDrawable(drawable);
}

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

কোটলিন

protected fun clearBackground() {
    BackgroundManager.getInstance(this).drawable = defaultBackground
}

protected fun getDefaultItemViewSelectedListener(): OnItemViewSelectedListener =
        OnItemViewSelectedListener { _, item, _, _ ->
            if (item is Movie) {
                item.getBackdropDrawable().also { background ->
                    updateBackground(background)
                }
            } else {
                clearBackground()
            }
        }

জাভা

protected void clearBackground() {
    BackgroundManager.getInstance(this).setDrawable(defaultBackground);
}

protected OnItemViewSelectedListener getDefaultItemViewSelectedListener() {
    return new OnItemViewSelectedListener() {
        @Override
        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
                RowPresenter.ViewHolder rowViewHolder, Row row) {
            if (item instanceof Movie ) {
                Drawable background = ((Movie)item).getBackdropDrawable();
                updateBackground(background);
            } else {
                clearBackground();
            }
        }
    };
}

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