পেজিং লাইব্রেরি একটি বৃহত্তর ডেটাসেট থেকে পেজ করা ডেটা লোড এবং প্রদর্শন করার জন্য শক্তিশালী সক্ষমতা প্রদান করে। এই নির্দেশিকাটিতে দেখানো হয়েছে কিভাবে পেজিং লাইব্রেরি ব্যবহার করে একটি নেটওয়ার্ক ডেটা সোর্স থেকে পেজ করা ডেটার একটি স্ট্রিম সেট আপ করতে হয় এবং সেটিকে একটি লেজি লিস্টে প্রদর্শন করতে হয়।
একটি ডেটা উৎস সংজ্ঞায়িত করুন
প্রথম ধাপ হলো ডেটা সোর্স শনাক্ত করার জন্য একটি PagingSource ইমপ্লিমেন্টেশন সংজ্ঞায়িত করা। PagingSource API ক্লাসে load মেথডটি অন্তর্ভুক্ত থাকে, যা আপনি সংশ্লিষ্ট ডেটা সোর্স থেকে পেজ করা ডেটা কীভাবে পুনরুদ্ধার করবেন তা নির্দেশ করার জন্য ওভাররাইড করতে পারেন।
অ্যাসিঙ্ক লোডিংয়ের জন্য কোটলিন কো-রুটিন ব্যবহার করতে সরাসরি PagingSource ক্লাসটি ব্যবহার করুন।
কী এবং ভ্যালু টাইপ নির্বাচন করুন
PagingSource<Key, Value> দুটি টাইপ প্যারামিটার আছে: Key এবং Value । Key প্যারামিটারটি ডেটা লোড করার জন্য ব্যবহৃত আইডেন্টিফায়ারকে সংজ্ঞায়িত করে এবং Value হলো ডেটার নিজস্ব টাইপ। উদাহরণস্বরূপ, যদি আপনি Retrofit- এ Int পেজ নম্বর পাস করে নেটওয়ার্ক থেকে User অবজেক্টের পেজ লোড করেন, তাহলে Key টাইপ হিসেবে Int এবং Value টাইপ হিসেবে User নির্বাচন করুন।
পেজিং উৎস সংজ্ঞায়িত করুন
নিম্নলিখিত উদাহরণটি একটি PagingSource বাস্তবায়ন করে যা পৃষ্ঠা নম্বর অনুসারে আইটেমের পৃষ্ঠাগুলি লোড করে। Key টাইপটি হল Int এবং Value টাইপটি হল User ।
class ExamplePagingSource(
val backend: ExampleBackendService,
val query: String
) : PagingSource<Int, User>() {
override suspend fun load(
params: LoadParams<Int>
): LoadResult<Int, User> {
init {
// the data source is expected to be immutable
// invalidate PagingSource if data source
// has updated
backEnd.addDatabaseOnChangedListener {
invalidate()
}
}
try {
// Start refresh at page 1 if undefined.
val nextPageNumber = params.key ?: 1
val response = backend.searchUsers(query, nextPageNumber)
return LoadResult.Page(
data = response.users,
prevKey = null, // Only paging forward.
nextKey = nextPageNumber + 1
)
} catch (e: Exception) {
// Handle errors in this block and return LoadResult.Error for
// expected errors (such as a network failure).
}
}
override fun getRefreshKey(state: PagingState<Int, User>): Int? {
// Try to find the page key of the closest page to anchorPosition from
// either the prevKey or the nextKey; you need to handle nullability
// here.
// * prevKey == null -> anchorPage is the first page.
// * nextKey == null -> anchorPage is the last page.
// * both prevKey and nextKey are null -> anchorPage is the
// initial page, so return null.
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
}
}
একটি সাধারণ PagingSource ইমপ্লিমেন্টেশন কোনো কোয়েরির জন্য উপযুক্ত ডেটা লোড করতে এর কনস্ট্রাক্টরে প্রদত্ত প্যারামিটারগুলোকে load মেথডে পাস করে। উপরের উদাহরণে, সেই প্যারামিটারগুলো হলো:
-
backend: ব্যাকএন্ড সার্ভিসের একটি ইনস্ট্যান্স যা ডেটা সরবরাহ করে। -
query:backendদ্বারা নির্দেশিত সার্ভিসে পাঠানোর জন্য সার্চ কোয়েরি।
LoadParams অবজেক্টটিতে যে লোড অপারেশনটি করা হবে সে সম্পর্কিত তথ্য থাকে। এর মধ্যে অন্তর্ভুক্ত রয়েছে যে কী-টি লোড করতে হবে এবং আইটেমের সংখ্যা।
LoadResult অবজেক্টটিতে লোড অপারেশনের ফলাফল থাকে। LoadResult একটি সিলড ক্লাস যা load কলটি সফল হয়েছে কিনা তার উপর নির্ভর করে তিনটি রূপের মধ্যে একটি গ্রহণ করে:
- লোড সফল হলে, একটি
LoadResult.Pageঅবজেক্ট রিটার্ন করুন। - লোড সফল না হলে, একটি
LoadResult.Errorঅবজেক্ট রিটার্ন করুন। - যদি
PagingSourceআর বৈধ না থাকে এবং এটিকে একটি নতুন ইনস্ট্যান্স দ্বারা প্রতিস্থাপন করার প্রয়োজন হয় (উদাহরণস্বরূপ, অন্তর্নিহিত ডেটার পরিবর্তনের কারণে), তাহলে একটিLoadResult.Invalidঅবজেক্ট রিটার্ন করুন।
নিম্নলিখিত চিত্রটি দেখায় যে কীভাবে এই উদাহরণে load ফাংশনটি প্রতিটি লোডের জন্য কী গ্রহণ করে এবং পরবর্তী লোডের জন্য কী সরবরাহ করে।
load কীভাবে কী ব্যবহার ও আপডেট করে, তা দেখানো ডায়াগ্রাম। PagingSource ইমপ্লিমেন্টেশনকে অবশ্যই একটি getRefreshKey মেথডও ইমপ্লিমেন্ট করতে হবে, যা প্যারামিটার হিসেবে একটি PagingState অবজেক্ট গ্রহণ করে। প্রাথমিক লোডের পর ডেটা রিফ্রেশ বা ইনভ্যালিডেট করা হলে, এটি load মেথডে পাস করার জন্য কী (key) রিটার্ন করে। Paging লাইব্রেরি পরবর্তী ডেটা রিফ্রেশের সময় স্বয়ংক্রিয়ভাবে এই মেথডটি কল করে।
ত্রুটিগুলি পরিচালনা করুন
বিভিন্ন কারণে ডেটা লোড করার অনুরোধ ব্যর্থ হতে পারে, বিশেষ করে নেটওয়ার্কের মাধ্যমে লোড করার সময়। লোড করার সময় যে ত্রুটিগুলো দেখা দেয়, তা রিপোর্ট করতে load মেথড থেকে একটি LoadResult.Error অবজেক্ট রিটার্ন করুন।
উদাহরণস্বরূপ, পূর্ববর্তী উদাহরণের ExamplePagingSource এর load মেথডে নিম্নলিখিতটি যোগ করে আপনি লোডিং ত্রুটিগুলি ধরতে এবং রিপোর্ট করতে পারেন:
catch (e: IOException) {
// IOException for network failures.
return LoadResult.Error(e)
} catch (e: HttpException) {
// HttpException for any non-2xx HTTP status codes.
return LoadResult.Error(e)
}
Retrofit ত্রুটিগুলি পরিচালনা করার বিষয়ে আরও তথ্যের জন্য, PagingSource API রেফারেন্সে থাকা নমুনাগুলি দেখুন।
PagingSource LoadResult.Error অবজেক্টগুলো সংগ্রহ করে UI-তে পৌঁছে দেয়, যাতে আপনি সেগুলোর উপর ভিত্তি করে ব্যবস্থা নিতে পারেন। UI-তে লোডিং অবস্থা প্রকাশ করার বিষয়ে আরও তথ্যের জন্য, “লোডিং অবস্থা পরিচালনা ও উপস্থাপন” দেখুন।
পেজিং ডেটার একটি প্রবাহ সেট আপ করুন
এরপরে, আপনার PagingSource ইমপ্লিমেন্টেশন থেকে পেজ করা ডেটার একটি স্ট্রিম প্রয়োজন। আপনার ViewModel এ ডেটা স্ট্রিমটি সেট আপ করুন। Pager ক্লাসটি এমন কিছু মেথড সরবরাহ করে যা একটি PagingSource থেকে PagingData অবজেক্টের একটি রিঅ্যাক্টিভ স্ট্রিম প্রকাশ করে। Paging লাইব্রেরিটি ডেটার স্ট্রিমটিকে একটি Flow হিসেবে প্রকাশ করে।
আপনার রিঅ্যাক্টিভ স্ট্রিম সেট আপ করার জন্য যখন আপনি একটি Pager ইনস্ট্যান্স তৈরি করেন, তখন আপনাকে অবশ্যই ইনস্ট্যান্সটিকে একটি PagingConfig কনফিগারেশন অবজেক্ট এবং এমন একটি ফাংশন প্রদান করতে হবে যা Pager বলে দেয় কীভাবে আপনার PagingSource ইমপ্লিমেন্টেশনের একটি ইনস্ট্যান্স পেতে হবে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে।
class UserViewModel(
private val backend: ExampleBackendService,
private val query: String
) : ViewModel() {
val userPagingFlow: Flow<PagingData<User>> = Pager(
// Configure how data is loaded by passing additional properties to
// PagingConfig, such as pageSize and enabling or disabling placeholders.
config = PagingConfig(
pageSize = 20,
enablePlaceholders = true
),
pagingSourceFactory = {
ExamplePagingSource(backend, query)
}
)
.flow
.cachedIn(viewModelScope)
}
cachedIn অপারেটরটি ডেটা স্ট্রিমকে শেয়ারযোগ্য করে তোলে এবং প্রদত্ত CoroutineScope ব্যবহার করে লোড করা ডেটা ক্যাশ করে রাখে। cachedIn ছাড়া ` PagingData পুনরায় সংগ্রহ করা যায় না। এই উদাহরণটিতে lifecycle-viewmodel-ktx আর্টিফ্যাক্ট দ্বারা প্রদত্ত ` viewModelScope ব্যবহার করা হয়েছে।
Pager অবজেক্টটি PagingSource অবজেক্টের load মেথডকে কল করে, এটিকে LoadParams অবজেক্টটি প্রদান করে এবং বিনিময়ে LoadResult অবজেক্টটি গ্রহণ করে।
আপনার UI-তে ডেটা সংগ্রহ ও প্রদর্শন করুন।
পেজড স্ট্রিমকে UI-এর সাথে সংযুক্ত করতে, আপনার ViewModel থেকে ফ্লো-টি নিন এবং সেটি আপনার লিস্ট কম্পোজেবল-এ পাস করুন।
@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
val userFlow = viewModel.userPagingFlow
UserList(flow = userFlow)
}
PagingData ফ্লো-কে LazyPagingItems এ রূপান্তর করতে collectAsLazyPagingItems ব্যবহার করুন। তারপর, প্রতিটি আইটেম বিন্যস্ত করতে একটি LazyColumn মধ্যে items API ব্যবহার করুন।
itemKey ব্যবহার করে প্রতিটি আইটেমের জন্য একটি অনন্য ও স্থিতিশীল শনাক্তকারী প্রদান করা নিশ্চিত করুন। নিম্নলিখিত উদাহরণে it.id (যা User.id প্রপার্টিকে নির্দেশ করে) ব্যবহার করা হয়েছে, কারণ ডেটা আপডেটের পরেও এটি User ইনস্ট্যান্সের জন্য স্থিতিশীল থাকে।
@Composable
fun UserList(flow: Flow<PagingData<User>>) {
val lazyPagingItems = flow.collectAsLazyPagingItems()
LazyColumn {
items(
lazyPagingItems.itemCount,
key = lazyPagingItems.itemKey { it.id }
) { index ->
val user = lazyPagingItems[index]
if (user != null) {
UserRow(user)
} else {
UserPlaceholder()
}
}
}
}
পেজিং লাইব্রেরি একটি পেজ লোড হওয়ার সময় প্লেসহোল্ডারগুলির জন্য null ব্যবহার করে, তাই আপনি যদি প্লেসহোল্ডারগুলি সক্রিয় করে থাকেন, তবে আপনাকে কন্টেন্ট ব্লকে null মানগুলি পরিচালনা করতে হবে।
এখন তালিকাটি পৃষ্ঠাবদ্ধ ডেটা প্রদর্শন করে এবং ব্যবহারকারী স্ক্রোল করার সাথে সাথে পেজিং লাইব্রেরি অতিরিক্ত পৃষ্ঠা লোড করে।
অতিরিক্ত সম্পদ
পেজিং লাইব্রেরি সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত রিসোর্সগুলো দেখুন:
ডকুমেন্টেশন
বিষয়বস্তু দেখুন
{% হুবহু %}আপনার জন্য প্রস্তাবিত
- দ্রষ্টব্য: জাভাস্ক্রিপ্ট বন্ধ থাকলেও লিঙ্কের লেখা প্রদর্শিত হয়।
- নেটওয়ার্ক এবং ডেটাবেস থেকে পৃষ্ঠা
- পেজিং ৩-এ স্থানান্তরিত করুন
- পেজিং লাইব্রেরির সংক্ষিপ্ত বিবরণ