टीवी पर चलने वाले मीडिया ऐप्लिकेशन में, उपयोगकर्ताओं को कॉन्टेंट ब्राउज़ करने, कोई आइटम चुनने, और कॉन्टेंट चलाना शुरू करने की सुविधा मिलनी चाहिए. कॉन्टेंट ब्राउज़ करने का अनुभव आसान और सहज होना चाहिए. साथ ही, यह देखने में अच्छा और दिलचस्प होना चाहिए.
इस गाइड में, बंद की गई androidx.leanback लाइब्रेरी से मिली क्लास का इस्तेमाल करके, अपने ऐप्लिकेशन के मीडिया कैटलॉग से संगीत या वीडियो ब्राउज़ करने के लिए यूज़र इंटरफ़ेस (यूआई) लागू करने का तरीका बताया गया है.
ध्यान दें: यहां दिखाए गए लागू करने के उदाहरण में, बंद की गई BrowseFragment क्लास के बजाय BrowseSupportFragment का इस्तेमाल किया गया है. BrowseSupportFragment क्लास का एक्सटेंशन है. इससे यह पक्का करने में मदद मिलती है कि सभी डिवाइसों और Android वर्शन पर एक जैसा व्यवहार हो.
Fragment
पहली इमेज. Leanback के सैंपल ऐप्लिकेशन का ब्राउज़ फ़्रैगमेंट, वीडियो कैटलॉग का डेटा दिखाता है.
मीडिया ब्राउज़ करने के लिए लेआउट बनाना
Leanback यूज़र इंटरफ़ेस (यूआई) टूलकिट में मौजूद 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>
ऐप्लिकेशन की मुख्य गतिविधि, इस व्यू को सेट करती है. जैसा कि यहां दिए गए उदाहरण में दिखाया गया है:
Kotlin
class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) } ...
Java
public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } ...
BrowseSupportFragment के तरीके, वीडियो डेटा और यूज़र इंटरफ़ेस (यूआई) एलिमेंट की मदद से व्यू को पॉप्युलेट करते हैं. साथ ही, आइकॉन और टाइटल जैसे लेआउट पैरामीटर सेट करते हैं. इसके अलावा, यह भी सेट करते हैं कि कैटगरी के हेडर चालू हैं या नहीं.
ऐप्लिकेशन की सबक्लास, BrowseSupportFragment के तरीकों को लागू करती है. साथ ही, यूज़र इंटरफ़ेस (यूआई) एलिमेंट पर उपयोगकर्ता की कार्रवाइयों के लिए इवेंट लिसनर सेट अप करती है और बैकग्राउंड मैनेजर तैयार करती है. जैसा कि यहां दिए गए उदाहरण में दिखाया गया है:
Kotlin
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() } ...
Java
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()); } ...
यूज़र इंटरफ़ेस (यूआई) एलिमेंट सेट अप करना
पिछले सैंपल में, निजी तरीका setupUIElements(), मीडिया कैटलॉग ब्राउज़र को स्टाइल करने के लिए, BrowseSupportFragment के कई तरीकों को कॉल करता है:
setBadgeDrawable()ब्राउज़ फ़्रैगमेंट के सबसे ऊपर दाएं कोने में, बताई गई ड्रॉएबल रिसॉर्स को रखता है. जैसा कि पहली और दूसरी इमेज में दिखाया गया है. अगरsetTitle()को भी कॉल किया जाता है, तो यह तरीका टाइटल स्ट्रिंग को ड्रॉएबल रिसॉर्स से बदल देता है. ड्रॉएबल रिसॉर्स की ऊंचाई 52 dp होनी चाहिए.setTitle()ब्राउज़ फ़्रैगमेंट के सबसे ऊपर दाएं कोने में टाइटल स्ट्रिंग सेट करता है. हालांकि, ऐसा तब होता है, जबsetBadgeDrawable()को कॉल न किया गया हो.setHeadersState()औरsetHeadersTransitionOnBackEnabled(), हेडर को छिपाते या बंद करते हैं. ज़्यादा जानकारी के लिए, हेडर छिपाना या बंद करना सेक्शन देखें.setBrandColor()ब्राउज़ फ़्रैगमेंट में यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए बैकग्राउंड का रंग सेट करता है. खास तौर पर, हेडर सेक्शन के बैकग्राउंड का रंग, बताई गई कलर वैल्यू के साथ सेट करता है.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 के साथ बाइंड करने का तरीका बताया गया है.
Kotlin
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 } }
Java
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()में, अपने व्यू को फ़ोकस किया जा सकने वाला बनाएं:Kotlin
override fun onBindViewHolder(viewHolder: Presenter.ViewHolder, o: Any) { val headerItem = (o as ListRow).headerItem val rootView = viewHolder.view rootView.focusable = View.FOCUSABLE // ... }
Java
@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() तरीके का इस्तेमाल करें. जैसा कि यहां दिए गए उदाहरण में दिखाया गया है.
Kotlin
setHeaderPresenterSelector(object : PresenterSelector() { override fun getPresenter(o: Any): Presenter { return IconHeaderItemPresenter() } })
Java
setHeaderPresenterSelector(new PresenterSelector() { @Override public Presenter getPresenter(Object o) { return new IconHeaderItemPresenter(); } });
पूरा उदाहरण देखने के लिए, Leanback का सैंपल ऐप्लिकेशन देखें .
हेडर छिपाना या बंद करना
कई बार, आपको पंक्ति के हेडर नहीं दिखाने होते. जैसे, जब स्क्रोल की जा सकने वाली सूची के लिए, ज़रूरत के मुताबिक कैटगरी न हों. पंक्ति के हेडर छिपाने या बंद करने के लिए, फ़्रैगमेंट के onActivityCreated()
तरीके के दौरान, BrowseSupportFragment.setHeadersState()
तरीके को कॉल करें. setHeadersState() तरीका, ब्राउज़ फ़्रैगमेंट में हेडर की शुरुआती स्थिति सेट करता है. इसके लिए, पैरामीटर के तौर पर इनमें से कोई एक कॉन्स्टैंट दिया जाता है:
HEADERS_ENABLED: ब्राउज़ फ़्रैगमेंट गतिविधि बनने पर, हेडर डिफ़ॉल्ट रूप से चालू होते हैं और दिखते हैं. इस पेज पर, पहली और दूसरी इमेज में दिखाए गए तरीके से हेडर दिखते हैं.HEADERS_HIDDEN: ब्राउज़ फ़्रैगमेंट गतिविधि बनने पर, हेडर डिफ़ॉल्ट रूप से चालू होते हैं और छिपे हुए होते हैं. स्क्रीन का हेडर सेक्शन छोटा हो जाता है. जैसा कि इमेज में कार्ड व्यू उपलब्ध कराना में दिखाया गया है. उपयोगकर्ता, हेडर सेक्शन को बड़ा करने के लिए, उसे चुन सकता है.HEADERS_DISABLED: ब्राउज़ फ़्रैगमेंट गतिविधि बनने पर, हेडर डिफ़ॉल्ट रूप से बंद होते हैं और कभी नहीं दिखते.
अगर HEADERS_ENABLED या HEADERS_HIDDEN सेट किया जाता है, तो पंक्ति में चुने गए कॉन्टेंट आइटम से वापस पंक्ति के हेडर पर जाने की सुविधा देने के लिए, setHeadersTransitionOnBackEnabled() को कॉल किया जा सकता है. अगर इस तरीके को कॉल नहीं किया जाता है, तो यह डिफ़ॉल्ट रूप से चालू रहता है. वापस जाने की सुविधा को खुद मैनेज करने के लिए, setHeadersTransitionOnBackEnabled() को false पास करें और अपना बैक स्टैक हैंडलिंग लागू करें.
मीडिया की सूचियां दिखाना
BrowseSupportFragment
क्लास की मदद से, मीडिया कैटलॉग से ब्राउज़ किए जा सकने वाले मीडिया कॉन्टेंट की कैटगरी और मीडिया आइटम तय किए और दिखाए जा सकते हैं. इसके लिए, अडैप्टर और प्रेजेंटर का इस्तेमाल किया जाता है. अडैप्टर की मदद से, स्थानीय या ऑनलाइन डेटा सोर्स से कनेक्ट किया जा सकता है. इनमें आपके मीडिया कैटलॉग की जानकारी होती है.
अडैप्टर, व्यू बनाने और स्क्रीन पर कोई आइटम दिखाने के लिए, उन व्यू में डेटा बाइंड करने के लिए प्रेजेंटर का इस्तेमाल करते हैं.
यहां दिए गए उदाहरण कोड में, स्ट्रिंग डेटा दिखाने के लिए Presenter को लागू करने का तरीका दिखाया गया है:
Kotlin
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 } }
Java
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 क्लास का इस्तेमाल किया गया है:
Kotlin
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 }
Java
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 का सैंपल ऐप्लिकेशन देखें .
बैकग्राउंड अपडेट करना
टीवी पर मीडिया ब्राउज़ करने वाले ऐप्लिकेशन को ज़्यादा दिलचस्प बनाने के लिए, उपयोगकर्ता के कॉन्टेंट ब्राउज़ करने के दौरान, बैकग्राउंड इमेज को अपडेट किया जा सकता है. इस तकनीक से, आपके ऐप्लिकेशन के साथ इंटरैक्ट करने का अनुभव ज़्यादा सिनेमैटिक और मज़ेदार हो सकता है.
Leanback यूज़र इंटरफ़ेस (यूआई) टूलकिट में, आपके टीवी ऐप्लिकेशन की गतिविधि का बैकग्राउंड बदलने के लिए, BackgroundManager
क्लास उपलब्ध है. यहां दिए गए उदाहरण में, आपके टीवी ऐप्लिकेशन की गतिविधि में बैकग्राउंड अपडेट करने के लिए, आसान तरीका बनाने का तरीका बताया गया है:
Kotlin
protected fun updateBackground(drawable: Drawable) { BackgroundManager.getInstance(this).drawable = drawable }
Java
protected void updateBackground(Drawable drawable) { BackgroundManager.getInstance(this).setDrawable(drawable); }
मीडिया ब्राउज़ करने वाले कई ऐप्लिकेशन, मीडिया लिस्टिंग में नेविगेट करने पर, बैकग्राउंड को अपने-आप अपडेट करते हैं. ऐसा करने के लिए, सिलेक्शन लिसनर सेट अप किया जा सकता है, ताकि उपयोगकर्ता के मौजूदा सिलेक्शन के आधार पर, बैकग्राउंड अपने-आप
अपडेट हो जाए. यहां दिए गए उदाहरण में, सिलेक्शन इवेंट को कैप्चर करने और बैकग्राउंड अपडेट करने के लिए, OnItemViewSelectedListener क्लास सेट अप करने का तरीका बताया गया है:
Kotlin
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() } }
Java
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(); } } }; }
ध्यान दें: पिछला उदाहरण, सिर्फ़ उदाहरण के तौर पर दिखाया गया है. अपने ऐप्लिकेशन में यह फ़ंक्शन बनाते समय, बेहतर परफ़ॉर्मेंस के लिए, बैकग्राउंड अपडेट करने की कार्रवाई को अलग थ्रेड में चलाएं. इसके अलावा, अगर आइटम स्क्रोल करने पर, बैकग्राउंड को अपडेट करने की योजना है, तो उपयोगकर्ता के किसी आइटम पर रुकने तक, बैकग्राउंड इमेज को अपडेट करने में लगने वाला समय जोड़ें. इस तकनीक से, बैकग्राउंड इमेज को बार-बार अपडेट करने से बचा जा सकता है.