onDestroy — Android-এ Activity এবং Fragment-এর জীবনচক্রের চূড়ান্ত পদ্ধতি, যা উপাদানের সম্পূর্ণ ধ্বংসের আগে কল করা হয়। onDestroy সংকেত দেয় যে Activity বা Fragment তার কাজ শেষ করছে: সমস্ত রিসোর্স মুক্ত করতে হবে, নেস্টেড ফ্র্যাগমেন্টগুলি ধ্বংস করতে হবে, ViewModel পরিষ্কার করতে হবে। Google-এর মতে, Activity সমাপ্তির 100% ক্ষেত্রে onDestroy কল করা হয়, কিন্তু প্রক্রিয়া মৃত্যুর (process death) সময় সিস্টেম onDestroy কল সম্পূর্ণরূপে এড়িয়ে যেতে পারে। onDestroy-এ Android ডকুমেন্টেশন জোর দেয় যে এই পদ্ধতি অস্বাভাবিক সমাপ্তিতে কলের গ্যারান্টি দেয় না।
মূল বিষয়
onDestroy — একটি কলব্যাক পদ্ধতি যা Android সম্পূর্ণরূপে Activity বা Fragment ধ্বংস করার আগে কল করে। এটি ডেভেলপারের জন্য রিসোর্স মুক্ত করা, ব্যাকগ্রাউন্ড অপারেশন বাতিল করা এবং ডেটা কাজ শেষ করার শেষ সুযোগ। onDestroy কার্যকর করার পর, Activity/Fragment ইনস্ট্যান্স আবর্জনা সংগ্রহ (GC) এর জন্য চিহ্নিত হয় এবং আর ব্যবহার করা যায় না।
onDestroy কল করার কারণ:
Google Android Vitals পরিসংখ্যান (2025) অনুসারে, সমস্ত Activity ধ্বংসের ঘটনার প্রায় 12% স্ক্রিন রোটেশনের কারণে, 65% finish()-এর কারণে এবং 23% কনফিগারেশন পরিবর্তনের কারণে ঘটে। onDestroy এড়িয়ে যাওয়া প্রক্রিয়া মৃত্যুর শতাংশ কম RAM (4 GB-এর কম) যুক্ত ডিভাইসের উপর নির্ভর করে প্রায় 5–8%।
onDestroy বেশিরভাগ সাধারণ পরিস্থিতিতে কল করা হয়, তবে গুরুত্বপূর্ণ ব্যতিক্রম রয়েছে যা ডেভেলপারকে বিবেচনা করতে হবে। onDestroy কলের গ্যারান্টি বোঝা অ্যাপ্লিকেশন আর্কিটেকচারের জন্য গুরুত্বপূর্ণ, বিশেষ করে ডেটা সংরক্ষণ এবং WorkManager কাজ বাতিল করার জন্য।
কখন onDestroy কল করা হয়:
কখন onDestroy কল করা হয় না:
onDestroy কলের গ্যারান্টির অভাবের কারণে, Google সুপারিশ করে: গুরুত্বপূর্ণ ডেটা সংরক্ষণের জন্য কখনই onDestroy-এর উপর নির্ভর করবেন না। onSaveInstanceState(), WorkManager বা স্বয়ংক্রিয় সংরক্ষণ সহ Room ব্যবহার করুন। onDestroy রিসোর্স মুক্ত করার জন্য, স্থায়িত্বের (persistence) জন্য নয়।
onDestroy Activity এবং Fragment উভয়ের জন্যই বিদ্যমান, তবে ভিন্ন চুক্তির সাথে। Fragment-এর জীবনচক্র আরও বিশদ: onDestroy ছাড়াও, onDestroyView (View স্তরবিন্যাস ধ্বংস) এবং onDetach (Activity থেকে বিচ্ছিন্ন) রয়েছে।
| উপাদান | ধ্বংসের পদ্ধতি | ক্রম | ViewModel বেঁচে থাকে |
|---|---|---|---|
| Activity | onDestroy | onPause → onStop → onDestroy | না (কেবল যদি ViewModelStore সংরক্ষিত না হয়) |
| Fragment | onDestroyView, onDestroy, onDetach | onPause → onStop → onDestroyView → onDestroy → onDetach | হ্যাঁ, যদি Fragment সরানো না হয় |
মূল পার্থক্য: Fragment-এর View নিজের Fragment-এর চেয়ে বেশি বার পুনরায় তৈরি হয়। স্ক্রিন রোটেশনের সময়, Fragment onDestroyView (View ধ্বংস) এর মধ্য দিয়ে যায়, কিন্তু Fragment নিজে এবং এর ViewModel জীবিত থাকে। onDestroyView মেমরি লিক এড়াতে View রেফারেন্স পরিষ্কার করার সঠিক জায়গা। Fragment-এর onDestroy Activity-র onDestroy-এর অনুরূপ, যা Fragment সম্পূর্ণরূপে সরানো হলে কল করা হয়।
চাইল্ড ফ্র্যাগমেন্টগুলি প্যারেন্ট Fragment-এর onDestroy-এর আগে ধ্বংস হয়। Activity-তে, চাইল্ড ফ্র্যাগমেন্টগুলি onDestroy পায় যখন প্যারেন্ট Activity-র onDestroy কল করা হয়। ক্রম নিশ্চিত: ফ্র্যাগমেন্টগুলি ধারণকারী Activity-র আগে শেষ হয়।
onDestroy সেই সমস্ত রিসোর্স মুক্ত করার জন্য যা Activity বা Fragment-এর বেশি বেঁচে থাকা উচিত নয়। onStop-এর বিপরীতে, যা ফিরে আসা পর্যন্ত রিসোর্স মুক্ত করে, onDestroy চূড়ান্ত পরিষ্কার করে।
onDestroy-এ বাধ্যতামূলক কাজের চেকলিস্ট:
onDestroy-এ কী করবেন না: onDestroy-এ ডেটা সংরক্ষণ করবেন না — onPause বা onSaveInstanceState ব্যবহার করুন। নতুন Service বা WorkManager কাজ শুরু করবেন না — Activity ধ্বংস হবে এবং আপনি ফলাফল ট্র্যাক করতে পারবেন না। UI আপডেট করার চেষ্টা করবেন না — View স্তরবিন্যাস ইতিমধ্যে ধ্বংস বা ধ্বংস হওয়ার প্রক্রিয়ায় আছে; findViewById() কল করলে null ফিরে আসবে।
ViewModel স্ক্রিন রোটেশনের সময় Activity-র onDestroy থেকে বাঁচার জন্য ডিজাইন করা হয়েছে, কিন্তু finish()-এর সময় Activity-র সাথে ধ্বংস হয়। এই অসমমিতিক আচরণ ডেভেলপারদের মধ্যে বিভ্রান্তির প্রধান কারণ।
স্ক্রিন রোটেশনের সময়:
finish()-এর সময় (ব্যবহারকারী “পিছনে” চাপলেন):
অতএব, onDestroy-এ viewModelScope বাতিল করা প্রয়োজন নয় — ViewModel নিজেই এটি করবে। আপনি যদি lifecycleScope (Activity-র সাথে আবদ্ধ, ViewModel-এর সাথে নয়) ব্যবহার করেন, তাহলে onDestroy-এ lifecycleScope.cancel() এর মাধ্যমে এটি বাতিল করুন অথবা Job ম্যানুয়ালি পরিচালনা করুন।
Activity-তে সঠিক lifecycleScope ব্যবস্থাপনা দেখায়: নেটওয়ার্ক অবস্থা পর্যবেক্ষণের জন্য একটি কোরুটিন চালু হয় এবং onDestroy-এ বাতিল হয়।
class NetworkMonitorActivity : AppCompatActivity() {
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d("NetworkMonitor", "নেটওয়ার্ক উপলব্ধ")
}
override fun onLost(network: Network) {
Log.d("NetworkMonitor", "নেটওয়ার্ক হারিয়ে গেছে")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_network)
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.registerDefaultNetworkCallback(networkCallback)
lifecycleScope.launch {
Log.d("NetworkMonitor", "নেটওয়ার্ক পর্যবেক্ষণ শুরু হয়েছে")
}
}
override fun onDestroy() {
super.onDestroy()
val connectivityManager = getSystemService(ConnectivityManager::class.java)
connectivityManager.unregisterNetworkCallback(networkCallback)
Log.d("NetworkMonitor", "onDestroy: কলব্যাক বাতিল করা হয়েছে")
}
}
onDestroy-এ, নেটওয়ার্ক কলব্যাক নিবন্ধন বাতিল করা হয়। lifecycleScope জীবনচক্র ধ্বংস হলে স্বয়ংক্রিয়ভাবে বাতিল হয় — আলাদা কোরুটিন বাতিলের প্রয়োজন নেই। নেটওয়ার্ক কলব্যাক নিবন্ধনমুক্ত করতে হবে, অন্যথায় Activity ধ্বংসের পরও এটি সিস্টেমে থাকবে।
Fragment onDestroyView-এ View রেফারেন্স সঠিকভাবে পরিষ্কার করে, ক্লোজারের কারণে মেমরি লিক প্রতিরোধ করে।
class ProfileFragment : Fragment() {
private var avatarView: ImageView? = null
private var progressBar: ProgressBar? = null
private val imageLoader = ImageLoader()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
avatarView = view.findViewById(R.id.avatar)
progressBar = view.findViewById(R.id.progress)
loadProfile()
}
private fun loadProfile() {
viewLifecycleOwner.lifecycleScope.launch {
try {
progressBar?.visibility = View.VISIBLE
val bitmap = imageLoader.load("https://example.com/avatar.png")
avatarView?.setImageBitmap(bitmap)
} finally {
progressBar?.visibility = View.GONE
}
}
}
override fun onDestroyView() {
super.onDestroyView()
avatarView = null
progressBar = null
imageLoader.cancel()
}
override fun onDestroy() {
super.onDestroy()
Log.d("ProfileFragment", "onDestroy: Fragment সম্পূর্ণরূপে ধ্বংস হয়েছে")
}
}
onDestroyView-এ, View রেফারেন্স null এ সেট করা হয় — এটি মেমরি লিক প্রতিরোধ করে যদি imageLoader-এ ক্লোজার avatarView-এর রেফারেন্স ধরে রাখে। Fragment নিজে এবং এর ViewModel onDestroy পর্যন্ত জীবিত থাকে। imageLoader.cancel() লোডিং বাতিল করে যদি Fragment স্ক্রিন ছেড়ে যায়।
isFinishing() ব্যবহার করে পার্থক্য করা যায় যে Activity ব্যবহারকারীর কমান্ডে শেষ হচ্ছে নাকি পুনর্নির্মাণের জন্য।
class AnalyticsActivity : AppCompatActivity() {
private val analytics = Analytics()
override fun onDestroy() {
if (isFinishing) {
Log.d("AnalyticsActivity", "Activity finish() দিয়ে শেষ হচ্ছে — বিশ্লেষণ পাঠানো হচ্ছে")
analytics.sendSessionEnd()
} else {
Log.d("AnalyticsActivity", "Activity পুনরায় তৈরি হচ্ছে (রোটেশন/কনফিগারেশন) — বিশ্লেষণ পাঠানো হচ্ছে না")
}
super.onDestroy()
}
}
isFinishing() পরীক্ষা করা বিশ্লেষণ, লগিং এবং সেশন ডেটা পরিষ্কারের জন্য একটি গুরুত্বপূর্ণ প্যাটার্ন। রোটেশনের সময়, সেশন শেষ ইভেন্ট পাঠানো উচিত নয় — ব্যবহারকারী এখনও অ্যাপ্লিকেশনের সাথে কাজ করছে। Google Analytics অনুসারে, ভুল isFinishing() পরীক্ষা 40% মিথ্যা সেশন ইভেন্টের কারণ।
সচরাচর জিজ্ঞাসিত প্রশ্ন
হ্যাঁ, হতে পারে — সিস্টেম দ্বারা প্রক্রিয়া মৃত্যু, ব্যবহারকারী দ্বারা ফোর্স স্টপ বা অস্বাভাবিক সমাপ্তির সময়। Google-এর মতে, প্রায় 5–8% Activity সমাপ্তি onDestroy কল ছাড়াই ঘটে। ডেভেলপারদের গুরুত্বপূর্ণ ডেটা সংরক্ষণের জন্য onDestroy-এর উপর নির্ভর করা উচিত নয় — onPause বা onSaveInstanceState ব্যবহার করুন।
finish() — একটি কল যা Activity ধ্বংস শুরু করে। onDestroy — একটি কলব্যাক যা finish() কার্যকর করার সময় কল হয়। সাধারণ সমাপ্তিতে onDestroy কল হওয়ার জন্য finish() প্রয়োজন। finish() সিস্টেম বা ডেভেলপার দ্বারা কল করা যেতে পারে, onDestroy কেবল একটি সিস্টেম কলব্যাক।
হ্যাঁ, অবশ্যই Activity এবং Fragment উভয়েই। super.onDestroy() ChildFragmentManager, LoaderManager এবং অন্যান্য সিস্টেম উপাদানের সঠিক পরিষ্কার নিশ্চিত করে। super.onDestroy() এড়িয়ে গেলে মেমরি লিক এবং ফ্র্যাগমেন্ট পুনরুদ্ধারে ত্রুটি হয়।
onCleared() Activity বা Fragment-এর onDestroy-এর পরে কল হয়, যখন ViewModel-এর আর প্রয়োজন নেই। স্ক্রিন রোটেশনের সময়, onCleared() কল হয় না — ViewModel onDestroy থেকে বেঁচে যায়। ক্রম: Activity/Fragment-এর onDestroy → (ViewModelStore পরিষ্কার হয়) → onCleared()।
প্রযুক্তিগতভাবে হ্যাঁ, তবে সুপারিশ করা হয় না। Activity onDestroy-এর পরপরই ধ্বংস হয়ে যায়, এবং শুরু করা Service নিয়ন্ত্রণহীন থাকে। ব্যাকগ্রাউন্ড কাজের জন্য, বিলম্ব সহ WorkManager ব্যবহার করুন: WorkManager Activity শেষ হওয়ার পরেও কার্যকর করার গ্যারান্টি দেয় এবং প্রক্রিয়া মৃত্যু থেকে বেঁচে যায়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন