1. ভূমিকা
অ্যান্ড্রয়েড ডিভাইসের ইকোসিস্টেম সর্বদা বিকশিত হচ্ছে। বিল্ট-ইন হার্ডওয়্যার কীবোর্ডের প্রাথমিক দিন থেকে শুরু করে ফ্লিপেবল, ফোল্ডেবল, ট্যাবলেট এবং ফ্রি-ফর্ম রিসাইজেবল উইন্ডোর আধুনিক ল্যান্ডস্কেপ - অ্যান্ড্রয়েড অ্যাপগুলি আজকের মতো এত বৈচিত্র্যময় ডিভাইসে কখনও চলেনি।
যদিও এটি ডেভেলপারদের জন্য দারুণ খবর, ব্যবহারের প্রত্যাশা পূরণ করতে এবং বিভিন্ন স্ক্রিন আকারে একটি চমৎকার ব্যবহারকারীর অভিজ্ঞতা অর্জনের জন্য কিছু অ্যাপ অপ্টিমাইজেশন প্রয়োজন। প্রতিটি নতুন ডিভাইসকে একবারে লক্ষ্য করার পরিবর্তে, একটি প্রতিক্রিয়াশীল/অভিযোজিত UI এবং স্থিতিস্থাপক স্থাপত্য আপনার অ্যাপটিকে আপনার বর্তমান এবং ভবিষ্যতের ব্যবহারকারীদের সর্বত্র - যেকোনো আকার এবং আকৃতির ডিভাইসে - দুর্দান্ত দেখাতে এবং কাজ করতে সাহায্য করতে পারে!
যেকোনো ডিভাইসের জন্য প্রস্তুত করার জন্য আপনার প্রতিক্রিয়াশীল/অ্যাডাপ্টিভ UI পরীক্ষা করার জন্য ফ্রি-ফর্ম রিসাইজেবল অ্যান্ড্রয়েড এনভায়রনমেন্টের প্রবর্তন একটি দুর্দান্ত উপায়। এই কোড ল্যাব আপনাকে রিসাইজ করার প্রভাবগুলি বোঝার পাশাপাশি একটি অ্যাপকে শক্তিশালী এবং সহজে আকার পরিবর্তন করার জন্য কিছু সেরা অনুশীলন বাস্তবায়নের জন্য গাইড করবে।
তুমি কী তৈরি করবে
আপনি ফ্রি-ফর্ম রিসাইজিংয়ের প্রভাবগুলি অন্বেষণ করবেন এবং রিসাইজ করার সর্বোত্তম অনুশীলনগুলি প্রদর্শনের জন্য একটি অ্যান্ড্রয়েড অ্যাপকে অপ্টিমাইজ করবেন। আপনার অ্যাপটি করবে:
একটি সামঞ্জস্যপূর্ণ ম্যানিফেস্ট রাখুন
- কোনও অ্যাপকে অবাধে আকার পরিবর্তন করতে বাধা দেয় এমন বিধিনিষেধগুলি সরান
আকার পরিবর্তন করার সময় অবস্থা বজায় রাখুন
- rememberSaveable ব্যবহার করে আকার পরিবর্তন করলে UI অবস্থা বজায় রাখে।
- UI আরম্ভ করার জন্য অপ্রয়োজনীয়ভাবে ব্যাকগ্রাউন্ডের কাজ নকল করা এড়িয়ে চলুন।
তোমার যা লাগবে
- বেসিক অ্যান্ড্রয়েড অ্যাপ্লিকেশন তৈরির জ্ঞান।
- কম্পোজে ভিউমডেল এবং স্টেট সম্পর্কে জ্ঞান
- একটি পরীক্ষামূলক ডিভাইস যা নিম্নলিখিতগুলির মধ্যে একটির মতো ফ্রি-ফর্ম উইন্ডো রিসাইজিং সমর্থন করে:
- ADB সেটআপ সহ একটি Chromebook
- একটি ট্যাবলেট যা Samsung DeX মোড বা উৎপাদনশীলতা মোড সমর্থন করে
- অ্যান্ড্রয়েড স্টুডিওতে ডেস্কটপ অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইস এমুলেটর
এই কোডল্যাবটি ব্যবহার করার সময় যদি আপনার কোনও সমস্যা (কোড বাগ, ব্যাকরণগত ত্রুটি, অস্পষ্ট শব্দ ইত্যাদি) দেখা দেয়, তাহলে অনুগ্রহ করে কোডল্যাবের নীচের বাম কোণে "একটি ভুল রিপোর্ট করুন" লিঙ্কের মাধ্যমে সমস্যাটি রিপোর্ট করুন।
2. শুরু করা
GitHub থেকে সংগ্রহস্থলটি ক্লোন করুন।
git clone https://github.com/android/large-screen-codelabs/
...অথবা রিপোজিটরির একটি জিপ ফাইল ডাউনলোড করুন এবং এটি এক্সট্র্যাক্ট করুন
আমদানি প্রকল্প
- অ্যান্ড্রয়েড স্টুডিও খুলুন
- ইমপোর্ট প্রজেক্ট অথবা ফাইল->নতুন->ইমপোর্ট প্রজেক্ট বেছে নিন।
- আপনি যেখানে প্রকল্পটি ক্লোন করেছেন বা এক্সট্র্যাক্ট করেছেন সেখানে নেভিগেট করুন।
- আকার পরিবর্তনকারী ফোল্ডারটি খুলুন।
- স্টার্ট ফোল্ডারে প্রজেক্টটি খুলুন। এতে স্টার্টার কোড রয়েছে।
অ্যাপটি ব্যবহার করে দেখুন
- অ্যাপটি তৈরি করুন এবং চালান
- অ্যাপটির আকার পরিবর্তন করে দেখুন
তুমি কি মনে করো?
আপনার টেস্ট ডিভাইসের সামঞ্জস্যতা সমর্থনের উপর নির্ভর করে, আপনি সম্ভবত লক্ষ্য করেছেন যে ব্যবহারকারীর অভিজ্ঞতা আদর্শ নয়। অ্যাপটির আকার পরিবর্তন করা যাচ্ছে না এবং প্রাথমিক আকৃতির অনুপাতের মধ্যে আটকে আছে। কী হচ্ছে?
ম্যানিফেস্ট সীমাবদ্ধতা
আপনি যদি অ্যাপটির AndroidManifest.xml ফাইলটি দেখেন, তাহলে দেখতে পাবেন যে কিছু বিধিনিষেধ যুক্ত করা হয়েছে যা আমাদের অ্যাপটিকে একটি মুক্ত-ফর্ম উইন্ডো রিসাইজিং পরিবেশে ভালভাবে কাজ করতে বাধা দিচ্ছে।
অ্যান্ড্রয়েডম্যানিফেস্ট.এক্সএমএল
android:maxAspectRatio="1.4"
android:resizeableActivity="false"
android:screenOrientation="portrait">
আপনার ম্যানিফেস্ট থেকে এই তিনটি সমস্যাযুক্ত লাইন মুছে ফেলার চেষ্টা করুন, অ্যাপটি পুনর্নির্মাণ করুন এবং আপনার পরীক্ষামূলক ডিভাইসে আবার চেষ্টা করুন। আপনি লক্ষ্য করবেন যে অ্যাপটি আর ফ্রি-ফর্ম রিসাইজিং থেকে সীমাবদ্ধ নয়। আপনার ম্যানিফেস্ট থেকে এই ধরণের বিধিনিষেধ অপসারণ করা আপনার অ্যাপটিকে ফ্রি-ফর্ম উইন্ডো রিসাইজিংয়ের জন্য অপ্টিমাইজ করার একটি গুরুত্বপূর্ণ পদক্ষেপ।
৩. আকার পরিবর্তনের কনফিগারেশন পরিবর্তন
যখন আপনার অ্যাপের উইন্ডোর আকার পরিবর্তন করা হয়, তখন আপনার অ্যাপের কনফিগারেশন আপডেট করা হয়। এই আপডেটগুলি আপনার অ্যাপের জন্য প্রভাব ফেলে। সেগুলি বোঝা এবং প্রত্যাশা করা আপনার ব্যবহারকারীদের একটি দুর্দান্ত অভিজ্ঞতা প্রদান করতে সাহায্য করতে পারে। সবচেয়ে স্পষ্ট পরিবর্তনগুলি হল আপনার অ্যাপ উইন্ডোর প্রস্থ এবং উচ্চতা, তবে এই পরিবর্তনগুলি আকৃতির অনুপাত এবং ওরিয়েন্টেশনের উপরও প্রভাব ফেলে।
কনফিগারেশন পরিবর্তনগুলি পর্যবেক্ষণ করা হচ্ছে
অ্যান্ড্রয়েড ভিউ সিস্টেম দিয়ে তৈরি একটি অ্যাপে এই পরিবর্তনগুলি নিজে ঘটছে কিনা তা দেখার জন্য, আপনি View.onConfigurationChanged ওভাররাইড করতে পারেন। Jetpack Compose-এ, আমাদের LocalConfiguration.current অ্যাক্সেস আছে, যা View.onConfigurationChanged কল করার সাথে সাথে স্বয়ংক্রিয়ভাবে আপডেট হয়।
আপনার নমুনা অ্যাপে এই কনফিগারেশন পরিবর্তনগুলি দেখতে, আপনার অ্যাপে একটি কম্পোজেবল যোগ করুন যা LocalConfiguration.current থেকে মান প্রদর্শন করে, অথবা এই ধরনের কম্পোজেবল দিয়ে একটি নতুন নমুনা প্রকল্প তৈরি করুন। এগুলি দেখার জন্য একটি উদাহরণ UI এরকম কিছু হতে পারে:
val configuration = LocalConfiguration.current
val isPortrait = configuration.orientation ==
Configuration.ORIENTATION_PORTRAIT
val screenLayoutSize =
when (configuration.screenLayout and
Configuration.SCREENLAYOUT_SIZE_MASK) {
SCREENLAYOUT_SIZE_SMALL -> "SCREENLAYOUT_SIZE_SMALL"
SCREENLAYOUT_SIZE_NORMAL -> "SCREENLAYOUT_SIZE_NORMAL"
SCREENLAYOUT_SIZE_LARGE -> "SCREENLAYOUT_SIZE_LARGE"
SCREENLAYOUT_SIZE_XLARGE -> "SCREENLAYOUT_SIZE_XLARGE"
else -> "undefined value"
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Text("screenWidthDp: ${configuration.screenWidthDp}")
Text("screenHeightDp: ${configuration.screenHeightDp}")
Text("smallestScreenWidthDp: ${configuration.smallestScreenWidthDp}")
Text("orientation: ${if (isPortrait) "portrait" else "landscape"}")
Text("screenLayout SIZE: $screenLayoutSize")
}
আপনি observing-configuration-changes প্রজেক্ট ফোল্ডারে একটি উদাহরণ বাস্তবায়ন দেখতে পাবেন। এটি আপনার অ্যাপের UI-তে যোগ করার চেষ্টা করুন, এটি আপনার পরীক্ষামূলক ডিভাইসে চালান এবং আপনার অ্যাপের কনফিগারেশন পরিবর্তনের সাথে সাথে UI আপডেটটি দেখুন।

আপনার অ্যাপের কনফিগারেশনে এই পরিবর্তনগুলি আপনাকে ছোট হ্যান্ডসেটে স্প্লিট স্ক্রিনের মাধ্যমে আমরা যে চরম পরিস্থিতি আশা করি তা থেকে ট্যাবলেট বা ডেস্কটপে পূর্ণ স্ক্রিনে দ্রুত সরে যাওয়ার অনুকরণ করতে দেয়। এটি কেবল স্ক্রিন জুড়ে আপনার অ্যাপের লেআউট পরীক্ষা করার একটি ভাল উপায় নয়, এটি আপনাকে দ্রুত কনফিগারেশন পরিবর্তন ইভেন্টগুলি কতটা ভালভাবে পরিচালনা করতে পারে তা পরীক্ষা করার অনুমতি দেয়।
৪. কার্যকলাপের জীবনচক্রের ইভেন্টগুলি লগ করা
আপনার অ্যাপের জন্য ফ্রি-ফর্ম উইন্ডো রিসাইজ করার আরেকটি অর্থ হল আপনার অ্যাপের জন্য বিভিন্ন Activity লাইফসাইকেল পরিবর্তন ঘটবে। রিয়েল টাইমে এই পরিবর্তনগুলি দেখতে, আপনার onCreate পদ্ধতিতে একটি লাইফসাইকেল পর্যবেক্ষক যোগ করুন এবং onStateChanged ওভাররাইড করে প্রতিটি নতুন লাইফসাইকেল ইভেন্ট লগ করুন।
lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
Log.d("resizing-codelab-lifecycle", "$event was called")
}
})
এই লগিং পদ্ধতি অনুসরণ করে, আপনার পরীক্ষামূলক ডিভাইসে আবার অ্যাপটি চালান, এবং আপনার অ্যাপটিকে ছোট করে আবার ফোরগ্রাউন্ডে আনার চেষ্টা করার সময় logcat দেখুন।
লক্ষ্য করুন যে আপনার অ্যাপটি মিনিমাইজ করার সময় পজ করা হয় এবং ফোরগ্রাউন্ডে আনা হলে আবার চালু করা হয়। এর ফলে আপনার অ্যাপের উপর প্রভাব পড়বে যা আপনি ধারাবাহিকতার উপর দৃষ্টি নিবদ্ধ করে এই কোডল্যাবের আসন্ন অংশে অন্বেষণ করবেন।

এখন লগক্যাটে দেখুন, যখন আপনি আপনার অ্যাপটিকে তার ক্ষুদ্রতম সম্ভাব্য আকার থেকে সর্বাধিক সম্ভাব্য আকারে রিসাইজ করেন তখন কোন অ্যাক্টিভিটি লাইফসাইকেল কলব্যাক ডাকা হয়।
আপনার পরীক্ষামূলক ডিভাইসের উপর নির্ভর করে, আপনি বিভিন্ন আচরণ লক্ষ্য করতে পারেন, কিন্তু আপনি সম্ভবত লক্ষ্য করেছেন যে আপনার অ্যাপের উইন্ডোর আকার উল্লেখযোগ্যভাবে পরিবর্তন করলে আপনার কার্যকলাপ ধ্বংস হয়ে যায় এবং পুনরায় তৈরি করা হয়, কিন্তু সামান্য পরিবর্তন করলে তা নয়। এর কারণ হল, API 24+ এ, শুধুমাত্র উল্লেখযোগ্য আকারের পরিবর্তনের ফলে Activity recreation দেখা দেয় ।
আপনি কিছু সাধারণ কনফিগারেশন পরিবর্তন দেখেছেন যা আপনি একটি মুক্ত-ফর্ম উইন্ডো পরিবেশে আশা করতে পারেন, তবে আরও কিছু পরিবর্তন সম্পর্কে সচেতন থাকতে হবে। উদাহরণস্বরূপ, যদি আপনার পরীক্ষামূলক ডিভাইসের সাথে একটি বহিরাগত মনিটর সংযুক্ত থাকে, তাহলে আপনি দেখতে পাবেন যে আপনার Activity ধ্বংস করা হয়েছে এবং ডিসপ্লে ঘনত্বের মতো কনফিগারেশন পরিবর্তনের জন্য পুনরায় তৈরি করা হয়েছে।
কনফিগারেশন পরিবর্তনের সাথে সম্পর্কিত কিছু জটিলতা সারাংশ করতে, আপনার অভিযোজিত UI বাস্তবায়নের জন্য WindowSizeClass এর মতো উচ্চ স্তরের API ব্যবহার করুন। ( বিভিন্ন স্ক্রিন আকার সমর্থন করুন দেখুন।)
৫. ধারাবাহিকতা - আকার পরিবর্তনের সময় কম্পোজেবলের অভ্যন্তরীণ অবস্থা বজায় রাখা
পূর্ববর্তী বিভাগে, আপনি কিছু কনফিগারেশন পরিবর্তন দেখেছেন যা আপনার অ্যাপটি একটি মুক্ত-ফর্ম উইন্ডো রিসাইজিং পরিবেশে আশা করতে পারে। এই বিভাগে, আপনি এই পরিবর্তনগুলির সময় আপনার অ্যাপের UI অবস্থা অবিচ্ছিন্ন রাখবেন।
প্রথমে NavigationDrawerHeader কম্পোজেবল ফাংশন ( ReplyHomeScreen.kt তে পাওয়া যায়) প্রসারিত করে ইমেল ঠিকানাটি ক্লিক করলে দেখানো হবে।
@Composable
private fun NavigationDrawerHeader(
modifier: Modifier = Modifier
) {
var showDetails by remember { mutableStateOf(false) }
Column(
modifier = modifier.clickable {
showDetails = !showDetails
}
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
ReplyLogo(
modifier = Modifier
.size(dimensionResource(R.dimen.reply_logo_size))
)
ReplyProfileImage(
drawableResource = LocalAccountsDataProvider
.userAccount.avatar,
description = stringResource(id = R.string.profile),
modifier = Modifier
.size(dimensionResource(R.dimen.profile_image_size))
)
}
AnimatedVisibility (showDetails) {
Text(
text = stringResource(id = LocalAccountsDataProvider
.userAccount.email),
style = MaterialTheme.typography.labelMedium,
modifier = Modifier
.padding(
start = dimensionResource(
R.dimen.drawer_padding_header),
end = dimensionResource(
R.dimen.drawer_padding_header),
bottom = dimensionResource(
R.dimen.drawer_padding_header)
),
)
}
}
}
যখন আপনি আপনার অ্যাপে প্রসারণযোগ্য হেডার যোগ করবেন,
- আপনার পরীক্ষামূলক ডিভাইসে অ্যাপটি চালান
- হেডারটি প্রসারিত করতে এটিতে আলতো চাপুন
- উইন্ডোর আকার পরিবর্তন করার চেষ্টা করুন
আপনি দেখতে পাবেন যে উল্লেখযোগ্যভাবে আকার পরিবর্তন করলে হেডারটি তার অবস্থা হারিয়ে ফেলে।

UI state হারিয়ে গেছে কারণ remember আপনাকে রিকম্পোজিশন জুড়ে state ধরে রাখতে সাহায্য করে, কিন্তু অ্যাক্টিভিটি বা প্রক্রিয়া পুনর্গঠন জুড়ে নয়। state hoisting ব্যবহার করা, composables কে stateless করার জন্য state কে composable এর কলারে স্থানান্তর করা সাধারণ, যা এই সমস্যাটি সম্পূর্ণরূপে এড়াতে পারে। যাইহোক, UI element state কে composable ফাংশনের অভ্যন্তরীণ রাখার সময় আপনি remember ব্যবহার করতে পারেন।
এই সমস্যাগুলি সমাধানের জন্য, remember এর পরিবর্তে rememberSaveable ব্যবহার করুন। এটি কাজ করে কারণ rememberSaveable মনে রাখা মানটি savedInstanceState এ সংরক্ষণ করে এবং পুনরুদ্ধার করে। remember to rememberSaveable পরিবর্তন করুন, পরীক্ষামূলক ডিভাইসে আপনার অ্যাপটি চালান এবং অ্যাপটির আকার পরিবর্তন করার চেষ্টা করুন। আপনি লক্ষ্য করবেন যে প্রসারণযোগ্য হেডারের অবস্থা রিসাইজ করার সময়, যেমনটি ইচ্ছাকৃতভাবে সংরক্ষিত থাকে।
৬. ব্যাকগ্রাউন্ড কাজের অপ্রয়োজনীয় নকল এড়ানো
আপনি দেখেছেন কিভাবে rememberSaveable ব্যবহার করে কম্পোজেবলের অভ্যন্তরীণ UI অবস্থা সংরক্ষণ করা যায়, যা ফ্রি-ফর্ম উইন্ডো রিসাইজিংয়ের ফলে প্রায়শই ঘটে। তবে, একটি অ্যাপের প্রায়শই UI অবস্থা এবং লজিককে composables থেকে দূরে সরিয়ে রাখা উচিত। রিসাইজিংয়ের সময় স্টেটের মালিকানা ViewModel-এ স্থানান্তর করা স্টেট সংরক্ষণের সেরা উপায়গুলির মধ্যে একটি। আপনি যখন আপনার স্টেটকে ViewModel এ উত্তোলন করেন, তখন আপনি দীর্ঘস্থায়ী ব্যাকগ্রাউন্ড কাজের সমস্যা যেমন ভারী ফাইল সিস্টেম অ্যাক্সেস বা নেটওয়ার্ক কলের সম্মুখীন হতে পারেন যা আপনার স্ক্রিনটি শুরু করার জন্য প্রয়োজনীয়।
আপনার কী ধরণের সমস্যার সম্মুখীন হতে পারেন তার একটি উদাহরণ দেখতে, ReplyViewModel এ initializeUIState পদ্ধতিতে একটি লগ স্টেটমেন্ট যোগ করুন।
fun initializeUIState() {
Log.d("resizing-codelab", "initializeUIState() called in the viewmodel")
val mailboxes: Map<MailboxType, List<Email>> =
LocalEmailsDataProvider.allEmails.groupBy { it.mailbox }
_uiState.value =
ReplyUiState(
mailboxes = mailboxes,
currentSelectedEmail = mailboxes[MailboxType.Inbox]?.get(0)
?: LocalEmailsDataProvider.defaultEmail
)
}
এখন আপনার পরীক্ষামূলক ডিভাইসে অ্যাপটি চালান, এবং আপনার অ্যাপের উইন্ডোটি কয়েকবার আকার পরিবর্তন করার চেষ্টা করুন।
Logcat এ দেখলে আপনি লক্ষ্য করবেন যে আপনার অ্যাপটি ইনিশিয়ালাইজেশন পদ্ধতিটি বেশ কয়েকবার রান করেছে। আপনার UI ইনিশিয়ালাইজ করার জন্য আপনি যে কাজটি একবার চালাতে চান তার জন্য এটি একটি সমস্যা হতে পারে। অতিরিক্ত নেটওয়ার্ক কল, ফাইল I/O, বা অন্যান্য কাজ ডিভাইসের কর্মক্ষমতা ব্যাহত করতে পারে এবং অন্যান্য অনিচ্ছাকৃত সমস্যার সৃষ্টি করতে পারে।
অপ্রয়োজনীয় ব্যাকগ্রাউন্ড কাজ এড়াতে, আপনার অ্যাক্টিভিটির onCreate() পদ্ধতি থেকে initializeUIState() কলটি সরিয়ে ফেলুন। পরিবর্তে, ViewModel এর init পদ্ধতিতে ডেটা ইনিশিয়ালাইজ করুন। এটি নিশ্চিত করে যে ReplyViewModel প্রথমবার ইনস্ট্যান্টিয়েট করার সময় ইনিশিয়ালাইজেশন পদ্ধতিটি কেবল একবারই চলবে:
init {
initializeUIState()
}
অ্যাপটি আবার চালানোর চেষ্টা করুন, এবং আপনি দেখতে পাবেন যে অপ্রয়োজনীয় সিমুলেটেড ইনিশিয়ালাইজেশন টাস্কটি কেবল একবারই কাজ করে, আপনি আপনার অ্যাপের উইন্ডোর আকার কতবার পরিবর্তন করেন তা নির্বিশেষে। এর কারণ হল ViewModels Activity এর জীবনচক্রের বাইরেও টিকে থাকে। ViewModel তৈরির সময় শুধুমাত্র একবার ইনিশিয়ালাইজিং কোড চালানোর মাধ্যমে, আমরা এটিকে যেকোনো Activity রিক্রিয়েশন থেকে আলাদা করি এবং অপ্রয়োজনীয় কাজ প্রতিরোধ করি। যদি এটি আসলে একটি ব্যয়বহুল সার্ভার কল বা আপনার UI আরম্ভ করার জন্য একটি ভারী ফাইল I/O অপারেশন হত, তাহলে আপনি উল্লেখযোগ্য সম্পদ সংরক্ষণ করতে পারতেন এবং আপনার ব্যবহারকারীর অভিজ্ঞতা উন্নত করতে পারতেন।
৭. অভিনন্দন!
তুমি এটা করেছো! দারুন কাজ! ChromeOS এবং অন্যান্য মাল্টি-উইন্ডো, মাল্টি-স্ক্রিন পরিবেশে অ্যান্ড্রয়েড অ্যাপগুলিকে ভালোভাবে আকার পরিবর্তন করতে সক্ষম করার জন্য তুমি এখন কিছু সেরা অনুশীলন বাস্তবায়ন করেছ।
নমুনা সোর্স কোড
GitHub থেকে সংগ্রহস্থলটি ক্লোন করুন
git clone https://github.com/android/large-screen-codelabs/
...অথবা রিপোজিটরির একটি জিপ ফাইল ডাউনলোড করুন এবং এটি এক্সট্র্যাক্ট করুন