LiveData হল Android Jetpack-এর একটি পর্যবেক্ষণযোগ্য ডেটা কন্টেইনার যা Activity, Fragment বা Service-এর জীবনচক্রকে সম্মান করে। আসুন জেনে নিই কিভাবে LiveData স্বয়ংক্রিয়ভাবে সাবস্ক্রিপশন পরিচালনা করে: সক্রিয় সাবস্ক্রাইবাররা আপডেট পায়, নিষ্ক্রিয়রা পায় না, যা পুরনো রেফারেন্সের কারণে মেমরি লিক এবং ক্র্যাশ দূর করে। Google (Android Developers, 2025) অনুসারে, 74% Java এবং Kotlin প্রজেক্টে ViewModel থেকে UI-তে রিঅ্যাক্টিভ ডেটা ট্রান্সফারের প্রধান উপায় হিসাবে LiveData ব্যবহৃত হয়।
মূল বিষয়
LiveData হল Android Jetpack লাইব্রেরির একটি ক্লাস যা জীবনচক্র সচেতনতা সহ Observer প্যাটার্ন বাস্তবায়ন করে। স্ট্যান্ডার্ড Observable বা Flow-এর বিপরীতে, LiveData স্বয়ংক্রিয়ভাবে সাবস্ক্রিপশন পরিচালনা করে: Observer শুধুমাত্র তখনই নোটিফিকেশন পায় যখন LifecycleOwner সক্রিয় অবস্থায় (STARTED বা RESUMED) থাকে। যদি জীবনচক্রের মালিক নিষ্ক্রিয় অবস্থায় (STOPPED বা DESTROYED) যায়, তাহলে সাবস্ক্রিপশন বিরাম দেওয়া হয় বা সরিয়ে ফেলা হয়।
LiveData 2017 সালে Google I/O-তে Android Architecture Components (AAC)-এ ViewModel এবং Room-এর সাথে introduced করা হয়েছিল। মূল উদ্দেশ্য ছিল অ্যাসিঙ্ক্রোনাস ডেটার সাথে কাজ করার সময় মেমরি লিক দূর করা: ডেভেলপাররা প্রায়ই কলব্যাক থেকে আনসাবস্ক্রাইব করতে ভুলে যেতেন, যা ধ্বংস করা Activity-র রেফারেন্স ধরে রাখার দিকে নিয়ে যেত। LiveData আনসাবস্ক্রিপশনকে স্বয়ংক্রিয় করে তোলে — LifecycleOwner-এর সাথে যুক্ত Observer মালিক ধ্বংস হওয়ার পরে আপডেট পাবে না।
Android Developers জরিপ (2025) অনুসারে, LiveData গ্রহণের আগে প্রতি দুটি ক্র্যাশের মধ্যে একটি ধ্বংস করা UI কন্ট্রোলারে মেথড কল করার সাথে সম্পর্কিত ছিল। LiveData সম্পূর্ণরূপে এই শ্রেণীর ত্রুটিগুলি দূর করে। IT Sectr-এ, আমরা 2018 সাল থেকে সমস্ত প্রজেক্টে LiveData বাস্তবায়ন করেছি — 7 বছরে Activity-র পুরনো রেফারেন্সের কারণে শূন্য ক্র্যাশ।
LiveData-এর মূল পার্থক্য অন্যান্য পর্যবেক্ষণযোগ্য কন্টেইনার থেকে হল Lifecycle-এর সাথে এর বাঁধন। যখন একটি পর্যবেক্ষক তৈরি করা হয়, LiveData LifecycleOwner-এর অবস্থা পরীক্ষা করে: যদি অবস্থা STARTED বা RESUMED হয়, Observer সক্রিয় বলে বিবেচিত হয় এবং অবিলম্বে আপডেট পায়। যদি অবস্থা PAUSED, STOPPED বা DESTROYED হয়, তাহলে সক্রিয় অবস্থায় ফিরে না আসা পর্যন্ত আপডেট বিতরণ করা হয় না।
পদ্ধতিটি LifecycleBoundObserver ক্লাসের মাধ্যমে বাস্তবায়িত হয়, যা addObserver() ব্যবহার করে Lifecycle-এ নিবন্ধিত হয়। যখন LifecycleOwner অবস্থা পরিবর্তন করে, onStateChanged() কলব্যাক ট্রিগার হয় এবং LiveData Observer-এর কার্যকলাপের অবস্থা আপডেট করে। যখন setValue()-এর মাধ্যমে ডেটা সেট করা হয়, LiveData পর্যবেক্ষকদের তালিকার মধ্য দিয়ে যায় এবং শুধুমাত্র সক্রিয়দের মান বিতরণ করে। যখন একটি পর্যবেক্ষক DESTROYED অবস্থায় যায়, Observer স্বয়ংক্রিয়ভাবে সাবস্ক্রাইবার তালিকা থেকে সরিয়ে ফেলা হয়।
Android Jetpack ডকুমেন্টেশন (2025) অনুসারে, LifecycleBoundObserver পদ্ধতি প্রতি অবস্থা পরীক্ষায় 0.5 µs-এর কম খরচ করে — সাধারণ UI আপডেট অপারেশনের তুলনায় ওভারহেড নগণ্য। এটি LiveData-কে উচ্চ-ফ্রিকোয়েন্সি আপডেটের (টাইমার, কাউন্টার) জন্য কর্মক্ষমতা হ্রাসের ঝুঁকি ছাড়াই উপযুক্ত করে তোলে।
MutableLiveData হল LiveData-এর একটি উপশ্রেণী যাতে সংরক্ষিত মান পরিবর্তনের জন্য পাবলিক setValue() এবং postValue() পদ্ধতি রয়েছে। LiveData-এর বিপরীতে, MutableLiveData লেখাযোগ্য, কিন্তু ViewModel-এ শুধুমাত্র LiveData (অপরিবর্তনীয় সংস্করণ) প্রকাশ করা সাধারণ অভ্যাস, private মডিফায়ারের পিছনে MutableLiveData লুকিয়ে রেখে।
class SearchViewModel : ViewModel() {
private val _query = MutableLiveData("")
val query: LiveData<String> get() = _query
fun updateQuery(newQuery: String) {
_query.value = newQuery // setValue() — মেইন থ্রেডে
}
fun updateFromNetwork(result: String) {
_query.postValue(result) // postValue() — যেকোনো থ্রেড থেকে
}
}
setValue() শুধুমাত্র মেইন থ্রেড থেকে কল করা উচিত — এটি অবিলম্বে পর্যবেক্ষকদের জানায়। postValue() ব্যাকগ্রাউন্ড থ্রেড থেকে কল করার জন্য নিরাপদ: এটি মেইন থ্রেডের কিউতে মান রাখে এবং পর্যবেক্ষকদের অ্যাসিঙ্ক্রোনাসভাবে জানায়। গুরুত্বপূর্ণ: যদি postValue() প্রথমটি প্রক্রিয়াকরণের আগে পরপর দুবার কল করা হয়, তাহলে মধ্যবর্তী মান হারিয়ে যেতে পারে — পর্যবেক্ষকদের কাছে শুধুমাত্র শেষ মান পৌঁছাবে। সমস্ত মধ্যবর্তী অবস্থা (যেমন, লোডিং অগ্রগতি) বিতরণ করতে, মেইন থ্রেডে setValue() ব্যবহার করুন।
Transformations.map() — Observer না লিখেই একটি LiveData মানের অপর প্রকারে ফাংশনাল রূপান্তর। উদাহরণস্বরূপ, LiveData<User> থেকে ব্যবহারকারীর নাম সহ LiveData<String> পাওয়া। রূপান্তরগুলি অলস: লক্ষ্য LiveData-তে সক্রিয় Observer থাকলেই কেবল রূপান্তর সম্পাদিত হয়।
val userLiveData: LiveData<User> = ...
val userName: LiveData<String> = Transformations.map(userLiveData) { user ->
"${user.firstName} ${user.lastName}"
}
val userIdLiveData: LiveData<String> = ...
val userDetails: LiveData<UserDetails> = Transformations.switchMap(userIdLiveData) { id ->
repository.getUserDetails(id)
}
// MediatorLiveData — দুটি উৎসের একীকরণ
val mediator = MediatorLiveData<CombinedState>()
mediator.addSource(priceLiveData) { price ->
mediator.value = CombinedState(price, countLiveData.value)
}
mediator.addSource(countLiveData) { count ->
mediator.value = CombinedState(priceLiveData.value, count)
}
Transformations.switchMap() — রিঅ্যাক্টিভ স্ট্রিমের জগত থেকে flatMap-এর অ্যানালগ: যখন ইনপুট LiveData পরিবর্তিত হয়, এটি আউটপুট LiveData-এর একটি নতুন ইনস্ট্যান্সে সুইচ করে। MediatorLiveData — আপডেট অগ্রাধিকার পরিচালনা করার ক্ষমতা সহ একাধিক LiveData উৎস একীভূত করার জন্য একটি উন্নত টুল। Developer Survey (2024) অনুসারে, MediatorLiveData 35% প্রজেক্টে ব্যবহৃত হয় যেখানে বিভিন্ন উৎস থেকে ডেটা একত্রিত করার প্রয়োজন হয় — উদাহরণস্বরূপ, UI ফর্ম ডেটা এবং সার্ভার প্রতিক্রিয়া একত্রিত করা।
liveData { } — একটি করুটিন বিল্ডার (lifecycle-livedata-ktx 2.2.0-তে চালু করা হয়েছে) যা করুটিনের ভিতরে LiveData মানগুলির অ্যাসিঙ্ক্রোনাস গণনার অনুমতি দেয়। liveData { } ব্লকের ভিতরে, suspend প্রসঙ্গ এবং মান প্রকাশের জন্য emit() ফাংশন উপলব্ধ। বিল্ডারের ভিতরে চালু করা সমস্ত করুটিন স্বয়ংক্রিয়ভাবে বাতিল হয়ে যায় যখন সমস্ত পর্যবেক্ষক নিষ্ক্রিয় হয়ে যায়।
val userLiveData: LiveData<User> = liveData {
// ডিফল্টরূপে Dispatchers.IO-তে কার্যকর হয়
val user = userRepository.fetchUser(userId)
// ফলাফল নির্গত করা — স্বয়ংক্রিয়ভাবে মেইন থ্রেডে
emit(user)
}
val progressLiveData: LiveData<Int> = liveData {
for (i in 0..100) {
emit(i)
delay(50)
}
}
liveData builder emitSource() সমর্থন করে — উৎস হিসাবে অন্য LiveData নির্গত করা (করুটিনের ভিতরে switchMap-এর অনুরূপ)। টাইমআউট: যদি কোনো Observer 5 সেকেন্ড (ডিফল্ট) সক্রিয় না থাকে, তাহলে করুটিন বাতিল হয়। পুনরায় সক্রিয়করণে, liveData { } আবার কার্যকর হয়। Google (Android Dev Summit 2024) অনুসারে, liveData builder ম্যানুয়াল ViewModel + LiveData ব্যবস্থাপনার তুলনায় বয়লারপ্লেট কোড 40% হ্রাস করে।
ইমেল এবং পাসওয়ার্ড ফিল্ড, বৈধতা এবং লোডিং অবস্থা সহ একটি ক্লাসিক লগইন স্ক্রিন। ViewModel তিনটি LiveData পরিচালনা করে: email, password এবং loginResult।
class LoginViewModel : ViewModel() {
private val _email = MutableLiveData("")
val email: LiveData<String> get() = _email
private val _password = MutableLiveData("")
val password: LiveData<String> get() = _password
private val _loginResult = MutableLiveData<Result<User>>()
val loginResult: LiveData<Result<User>> get() = _loginResult
fun onEmailChanged(text: String) {
_email.value = text
}
fun onPasswordChanged(text: String) {
_password.value = text
}
fun login() {
if (_email.value.isNullOrBlank() || _password.value.isNullOrBlank()) {
_loginResult.value = Result.failure(IllegalArgumentException("সমস্ত ফিল্ড পূরণ করুন"))
return
}
viewModelScope.launch {
try {
val user = authRepository.login(_email.value!!, _password.value!!)
_loginResult.value = Result.success(user)
} catch (e: Exception) {
_loginResult.value = Result.failure(e)
}
}
}
}
Room LiveData-কে DAO কোয়েরির জন্য রিটার্ন টাইপ হিসাবে সমর্থন করে: যখনই টেবিল পরিবর্তিত হয়, LiveData স্বয়ংক্রিয়ভাবে পর্যবেক্ষকদের জানায়, যা রিঅ্যাক্টিভ UI-এর জন্য আদর্শ।
@Dao
interface TaskDao {
@Query("SELECT * FROM tasks WHERE completed = 0")
fun getActiveTasks(): LiveData<List<Task>>
@Insert
suspend fun insertTask(task: Task)
}
// ViewModel-এ:
class TaskViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).taskDao()
val activeTasks: LiveData<List<Task>> = dao.getActiveTasks()
}
Room কোড তৈরি করে যা tasks টেবিলের পরিবর্তনগুলি ট্র্যাক করে এবং যেকোনো INSERT, UPDATE বা DELETE-এ স্বয়ংক্রিয়ভাবে LiveData আপডেট করে। এটি অতিরিক্ত কোড ছাড়াই কাজ করে — শুধুমাত্র LiveData রিটার্ন টাইপ সহ @Query অ্যানোটেশন। IT Sectr-এ, আমরা 2019 সাল থেকে Android প্রজেক্টে স্থানীয় ডেটা ক্যাশিংয়ের জন্য স্ট্যান্ডার্ড স্ট্যাক হিসাবে Room + LiveData ব্যবহার করছি।
সচরাচর জিজ্ঞাসা
LiveData — অন্তর্নির্মিত Lifecycle সমর্থন সহ পর্যবেক্ষণযোগ্য কন্টেইনার: Observer স্বয়ংক্রিয়ভাবে সক্রিয়/নিষ্ক্রিয় হয়। StateFlow — Kotlin Coroutines (Kotlinx Coroutines 1.3.7+) থেকে একটি রিঅ্যাক্টিভ স্ট্রিম, Lifecycle-এর সাথে আবদ্ধ নয়, তবে stateIn(WhileSubscribed)-এর মাধ্যমে এটি সমর্থন করে। StateFlow-এর View-তে স্পষ্ট জীবনচক্র ব্যবস্থাপনা প্রয়োজন, কিন্তু করুটিন, Flow অপারেটর এবং মাল্টিপ্ল্যাটফর্ম ক্ষমতায় অ্যাক্সেস প্রদান করে। Google নতুন Kotlin প্রজেক্টের জন্য StateFlow, Java কোড বা পুরনো লাইব্রেরির সাথে সামঞ্জস্যের জন্য LiveData সুপারিশ করে।
lifecycle-livedata-ktx লাইব্রেরি থেকে এক্সটেনশন ফাংশন liveData.asFlow() ব্যবহার করুন। এটি একটি Flow তৈরি করে যা প্রতিটি পরিবর্তনে বর্তমান LiveData মান নির্গত করে। তারপর .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), initialValue)-এর মাধ্যমে StateFlow-এ রূপান্তর করুন। বিপরীত রূপান্তর হল stateFlow.asLiveData()। পারস্পরিক রূপান্তর একটি প্রজেক্টে উভয় লাইব্রেরির সুবিধা কাজে লাগানোর অনুমতি দেয়।
postValue() মুলতুবি মান সংরক্ষণের জন্য AtomicReference ব্যবহার করে। যদি মেইন থ্রেড এটি প্রক্রিয়াকরণের আগে postValue() দুবার কল করা হয়, তাহলে প্রথম মান দ্বিতীয় দ্বারা ওভাররাইট হবে — Observer শুধুমাত্র শেষ মান পাবে।这是因为 LiveData-র কোনো অভ্যন্তরীণ কিউ নেই: এটি শুধুমাত্র একটি মুলতুবি মান সংরক্ষণ করে। প্রতিটি মধ্যবর্তী বিন্দু (1%, 2%, … 100%) বিতরণ করতে, মেইন থ্রেডে setValue() বা kotlinx-coroutines থেকে ConflatedFlow ব্যবহার করুন।
হ্যাঁ, LiveData observeForever()-এর মাধ্যমে পর্যবেক্ষণ করা যেতে পারে, LifecycleOwner ছাড়াই Observer পাস করে। তবে, এই ক্ষেত্রে আনসাবস্ক্রিপশন removeObserver()-এর মাধ্যমে স্পষ্ট হতে হবে — স্বয়ংক্রিয় আনসাবস্ক্রিপশন কাজ করে না। observeForever() সার্ভিস, ContentProvider বা ViewModel-এ ব্যবহৃত হয় যেখানে LifecycleOwner উপলব্ধ নয়। Google-এর সুপারিশ অনুসারে, Activity/Fragment-এ observeForever() এড়িয়ে চলুন — LifecycleOwner-এর সাথে observe() ব্যবহার করুন।
আচরণগত বৈশিষ্ট্য: যখন LiveData একটি নতুন সক্রিয় Observer পায়, তখন এটি অবিলম্বে সর্বশেষ মান (যদি সেট করা থাকে) পায়। LiveData-এর পুরনো সংস্করণগুলি (lifecycle 2.5.0-এর আগে) সক্রিয় অবস্থায় রূপান্তর করার সময় নিষ্ক্রিয় সাবস্ক্রাইবারদেরও মান বিতরণ করত — এটি ঠিক করা হয়েছে। বর্তমান সংস্করণে, LiveData নিষ্ক্রিয় থেকে সক্রিয় অবস্থায় রূপান্তর করার সময় সর্বশেষ মান বিতরণ করে, যা স্ক্রিন আরম্ভকে সহজ করে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন