Fragment Lifecycle হল কলব্যাক পদ্ধতির একটি কঠোরভাবে সংজ্ঞায়িত ক্রম যা Android Fragment-এর জীবনকাল ধরে কল করে: সৃষ্টি (onAttach) থেকে সম্পূর্ণ অপসারণ (onDetach) পর্যন্ত। Fragment-এর জীবনচক্র Activity-র চেয়ে বেশি জটিল — এতে 11টি অবস্থা ও 7টি প্রধান কলব্যাক অন্তর্ভুক্ত। Fragment Lifecycle FragmentManager-এর মাধ্যমে পরিচালিত হয় এবং এর হোস্ট Activity-র জীবনচক্রের সাথে ঘনিষ্ঠভাবে যুক্ত। Google-এর মতে, API Level 21+ এ চলা 74% Android অ্যাপ্লিকেশনে Fragment ব্যবহৃত হয়, যা পেশাদার Android উন্নয়নের জন্য Fragment Lifecycle বোঝা আবশ্যক করে তোলে। Fragment Lifecycle-এ Android ডকুমেন্টেশন সমস্ত অবস্থা ও কল গ্যারান্টি বর্ণনা করে।
মূল বিষয়
Fragment Lifecycle হল আন্তঃসংযুক্ত অবস্থা ও পদ্ধতির একটি সেট যার মাধ্যমে প্রতিটি Fragment ইনস্ট্যান্স সৃষ্টি থেকে ধ্বংস পর্যন্ত যায়। Activity-র বিপরীতে, Fragment-এর জীবনচক্র দুটি প্রসঙ্গের সাথে যুক্ত: Fragment নিজেই (onAttach থেকে onDetach পর্যন্ত বেঁচে থাকে) এবং এর View (onCreateView থেকে onDestroyView পর্যন্ত বেঁচে থাকে)। এই পৃথকীকরণ হল Fragment-এর একটি মূল বৈশিষ্ট্য, যা Fragment-কে নষ্ট না করে স্ক্রিন ঘোরানোর সময় View ধ্বংস থেকে বাঁচতে দেয়।
Fragment কলব্যাকের সম্পূর্ণ ক্রম:
Google-এর মতে, একটি আধুনিক অ্যাপ্লিকেশনে গড় fragment ব্যবহারকারী সেশনে 3–5 বার সম্পূর্ণ চক্রের মধ্য দিয়ে যায় (স্ক্রিন ঘোরানো ও নেভিগেশনের কারণে)। সমস্ত পর্যায়ের সঠিক পরিচালনা UI স্থিতিশীলতার ভিত্তি।
FragmentManager পাঁচটি প্রধান অবস্থার মাধ্যমে Fragment পরিচালনা করে, যা Fragment.State ক্লাসে সংজ্ঞায়িত। প্রতিটি অবস্থা কলব্যাকের একটি নির্দিষ্ট সেটের সাথে মিলে যায় যেগুলি কার্যকর করা হয়েছে।
| অবস্থা | অর্থ | কার্যকর করা কলব্যাক |
|---|---|---|
| INITIALIZED | Fragment তৈরি হয়েছে, কিন্তু View এখনও উপলব্ধ নয় | onAttach, onCreate |
| CREATED | View তৈরি হয়েছে, কিন্তু Fragment দৃশ্যমান নয় | + onCreateView, onViewCreated |
| STARTED | Fragment দৃশ্যমান, কিন্তু সক্রিয় নয় | + onStart |
| RESUMED | Fragment সক্রিয়, ব্যবহারকারীর সাথে ইন্টারঅ্যাক্ট করে | + onResume |
| DESTROYED | Fragment নষ্ট হয়েছে | + onDestroyView, onDestroy, onDetach |
FragmentManager ব্যবহারকারীর ক্রিয়া ও সিস্টেম ইভেন্টের উপর ভিত্তি করে Fragment-কে অবস্থার মধ্যে স্থানান্তর করে। কন্টেইনারে Fragment যোগ করার সময়, এটি ক্রমান্বয়ে INITIALIZED → CREATED → STARTED → RESUMED এর মধ্য দিয়ে যায়। অপসারণের সময় — RESUMED → STARTED → CREATED → DESTROYED।
CREATED অবস্থাটি বিশেষ: View নষ্ট হতে পারে (onDestroyView-এর পরে), কিন্তু Fragment নিজেই CREATED অবস্থায় থাকে (onDestroyView-এর পরে, onDestroy-এর আগে)। এটি FragmentManager-কে View ছাড়া মেমরিতে Fragment রাখতে দেয়, যা স্ক্রিন ঘোরানো থেকে বাঁচার জন্য প্রয়োজনীয়।
Fragment Lifecycle ও Activity Lifecycle ঘনিষ্ঠভাবে সম্পর্কিত কিন্তু মৌলিক পার্থক্য রয়েছে। Fragment সর্বদা Activity-র ভিতরে থাকে এবং এর জীবনচক্র হোস্ট Activity-র উপর নির্ভর করে, কিন্তু তার সমান নয়।
| দিক | Activity | Fragment |
|---|---|---|
| কলব্যাকের সংখ্যা | 7 (onCreate … onDestroy) | 11 (onAttach … onDetach) |
| View-এর জন্য পৃথক Lifecycle | না | হ্যাঁ (viewLifecycleOwner) |
| ঘোরানো থেকে বাঁচে | না (নষ্ট হয়) | হ্যাঁ (ViewModel + Fragment বেঁচে থাকে) |
| হোস্টের উপর নির্ভরতা | না | Activity Lifecycle-এর উপর নির্ভর করে |
| অবস্থা সংরক্ষণ | onSaveInstanceState | onSaveInstanceState (Fragment স্তরে) |
| ব্যবস্থাপনা | সিস্টেম | FragmentManager |
মূল ব্যবহারিক পার্থক্য: স্ক্রিন ঘোরানোর সময়, Activity সম্পূর্ণরূপে নষ্ট (onDestroy) এবং পুনরায় তৈরি (onCreate) হয়। Fragment ঘোরানোর সময় onDestroyView (View নষ্ট) → onCreateView (View পুনরায় তৈরি) এর মধ্য দিয়ে যায়, কিন্তু Fragment নিজে ও তার ViewModel বেঁচে থাকে। এটি Fragment-কে UI লজিকের জন্য আদর্শ কন্টেইনার করে তোলে যা কনফিগারেশন পরিবর্তন থেকে বাঁচতে হবে।
স্ক্রিন ঘোরানোর সময় কল ক্রম: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity নষ্ট) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume।
FragmentManager হল কেন্দ্রীয় ক্লাস যা fragments যোগ, অপসারণ, প্রতিস্থাপন ও তাদের অবস্থা পরিচালনার জন্য দায়িত্বশীল। FragmentManager BackStack বজায় রাখে এবং লেনদেনের সময় কলব্যাকের সঠিক ক্রম নিশ্চিত করে। প্রতিটি Activity ও প্রতিটি নেস্টেড Fragment-এর নিজস্ব FragmentManager থাকে।
FragmentManager-এর প্রধান কার্যক্রম:
BackStack হল FragmentManager-এর লেনদেন স্ট্যাক। সিস্টেম Back বাটন চাপলে, BackStack-এর শেষ লেনদেন রোল ব্যাক করা হয় (popBackStack())। popBackStack-এর মাধ্যমে সরানো Fragment পুনরুদ্ধার হয়। BackStack খালি থাকলে, Back চাপলে Activity শেষ হয়।
Google-এর মতে, 78% Fragment সমস্যা (ডুপ্লিকেশন, খালি স্ক্রিন, IllegalStateException) FragmentManager-এর ভুল ব্যবহারের সাথে সম্পর্কিত। মূল নিয়ম: প্রসঙ্গ অনুসারে commit() (এসিনক্রোনাস) বা commitNow() (সিনক্রোনাস) এর মাধ্যমে লেনদেন কার্যকর করুন। commit() একাধিক লেনদেনের অধীনে সঠিক ক্রম নিশ্চিত করে।
Fragment onSaveInstanceState-এর মাধ্যমে নিজস্ব অবস্থা সংরক্ষণ প্রক্রিয়া সমর্থন করে, যা Activity থেকে স্বাধীনভাবে কাজ করে। Fragment একটি Bundle-এ অবস্থা সংরক্ষণ করে যা পুনরুদ্ধারের সময় onCreate ও onCreateView-এ পাঠানো হয়।
কখন Fragment অবস্থা সংরক্ষণ করে:
আধুনিক পদ্ধতি: Fragment অবস্থা সংরক্ষণের জন্য ViewModel-এ SavedStateHandle ব্যবহার করুন। SavedStateHandle স্বয়ংক্রিয়ভাবে স্ক্রিন ঘোরানো ও প্রক্রিয়া মৃত্যুতে ডেটা সংরক্ষণ ও পুনরুদ্ধার করে, ম্যানুয়াল onSaveInstanceState-এর প্রয়োজন ছাড়াই। Google Fragment-এ UI অবস্থা সংরক্ষণের জন্য SavedStateHandle-কে পছন্দের উপায় হিসেবে সুপারিশ করে।
setRetainInstance (Fragment 1.3 থেকে অপ্রচলিত): আগে Fragment স্ক্রিন ঘোরানোর সময় setRetainInstance(true)-এর মাধ্যমে সংরক্ষিত থাকতে পারত। এই পদ্ধতি ViewModel + SavedStateHandle দ্বারা প্রতিস্থাপিত হয়েছে, যা আরও নির্ভরযোগ্যভাবে কাজ করে এবং বিশেষ কনফিগারেশনের প্রয়োজন হয় না।
viewLifecycleOwner হল Fragment View-এর সাথে যুক্ত Lifecycle (onCreateView থেকে onDestroyView পর্যন্ত)। এটি একটি মৌলিক গুরুত্বপূর্ণ ধারণা: viewLifecycleOwner-এর মাধ্যমে LiveData/Flow-এ করা সাবস্ক্রিপশন View নষ্ট (onDestroyView) হলে স্বয়ংক্রিয়ভাবে বাতিল হয়, কিন্তু Fragment নিজেকে প্রভাবিত করে না।
viewLifecycleOwner ও Fragment lifecycle-এর মধ্যে পার্থক্য:
কেন এটি গুরুত্বপূর্ণ: আপনি যদি Fragment lifecycle (this)-এর মাধ্যমে LiveData-তে সাবস্ক্রাইব করেন, onDestroyView-এর পর সাবস্ক্রিপশন সক্রিয় থাকে এবং LiveData একটি শূন্য View আপডেট করার চেষ্টা করে, যা NPE ঘটায়। viewLifecycleOwner-এর মাধ্যমে সাবস্ক্রাইব করা গ্যারান্টি দেয় যে onDestroyView-এর পর কোনো UI আপডেট হবে না।
নিয়ম: Fragment-এ, LiveData, Flow ও UI-সম্পর্কিত করুটিনের সাবস্ক্রিপশনের জন্য সর্বদা viewLifecycleOwner ব্যবহার করুন। ViewModel করুটিনের জন্য viewModelScope ব্যবহার করুন — এটি Fragment-এর পরিবর্তে ViewModel-এর সাথে যুক্ত।
সঠিক UI আরম্ভকরণ ও viewLifecycleOwner-এর মাধ্যমে LiveData সাবস্ক্রিপশন প্রদর্শন করে।
class UserListFragment : Fragment() {
private val viewModel: UserListViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_user_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val button: Button = view.findViewById(R.id.load_button)
button.setOnClickListener { viewModel.loadUsers() }
viewModel.users.observe(viewLifecycleOwner) { users ->
Log.d("UserListFragment", "তালিকা আপডেট হচ্ছে: ${users.size} ব্যবহারকারী")
}
}
override fun onDestroyView() {
super.onDestroyView()
Log.d("UserListFragment", "onDestroyView: View নষ্ট হয়েছে")
}
}
Fragment onCreateView-এ লেআউট ইনফ্লেট করে, UI কনফিগার করে ও onViewCreated-এ LiveData-তে সাবস্ক্রাইব করে। viewLifecycleOwner-এর মাধ্যমে সাবস্ক্রিপশন লিক প্রতিরোধের জন্য বাধ্যতামূলক। onDestroyView View ধ্বংস লগ করে — নিশ্চিতকরণ যে Fragment স্ক্রিন ঘোরানো থেকে বাঁচে।
Activity-তে FragmentManager-এর মাধ্যমে Fragment যোগ, BackStack-সহ প্রতিস্থাপন ও পুনরুদ্ধার প্রদর্শন করে।
class HostActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, HomeFragment())
.addToBackStack(null)
.commit()
}
}
fun openDetail(userId: String) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, DetailFragment.newInstance(userId))
.addToBackStack(null)
.commit()
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportFragmentManager.popBackStack()
} else {
super.onBackPressed()
}
}
}
class DetailFragment : Fragment() {
companion object {
fun newInstance(userId: String): DetailFragment {
return DetailFragment().apply {
arguments = Bundle().apply { putString("user_id", userId) }
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val userId = arguments?.getString("user_id")
Log.d("DetailFragment", "ব্যবহারকারীর বিবরণ লোড হচ্ছে: $userId")
}
}
Activity fragments পরিচালনার জন্য supportFragmentManager ব্যবহার করে। BackStack-সহ add() লেনদেন নিশ্চিত করে যে Back চাপলে HomeFragment পুনরুদ্ধার হয়। openDetail() বর্তমান Fragment-কে DetailFragment দিয়ে আর্গুমেন্টসহ প্রতিস্থাপন করে। savedInstanceState == null-এর পরীক্ষা স্ক্রিন ঘোরানোর সময় fragment ডুপ্লিকেশন প্রতিরোধ করে।
প্রতিক্রিয়াশীল UI আপডেটের জন্য viewLifecycleOwner-সহ Fragment-এ Flow ও StateFlow ব্যবহার।
class SearchFragment : Fragment() {
private val viewModel: SearchViewModel by viewModels()
private var binding: FragmentSearchBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentSearchBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding?.searchButton?.setOnClickListener {
viewModel.search(binding?.queryInput?.text.toString())
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.searchResults.collectLatest { results ->
Log.d("SearchFragment", "অনুসন্ধান ফলাফল: ${results.size}")
}
}
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
}
Fragment View অ্যাক্সেসের জন্য View Binding ব্যবহার করে। viewLifecycleOwner.lifecycleScope.launch করুটিন View নষ্ট হলে স্বয়ংক্রিয়ভাবে বাতিল হয়। লিক প্রতিরোধের জন্য onDestroyView-এ binding শূন্য করা হয়। StateFlow View পুনরায় তৈরি হলে ডেটার সতেজতা নিশ্চিত করে।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
onCreateView Fragment-এর মূল View তৈরি ও ফেরত দেয়। onViewCreated View তৈরির পরপরই কল করা হয়, গ্যারান্টি দেয় যে View সম্পূর্ণরূপে আরম্ভ ও কনফিগারেশন (findViewById, সাবস্ক্রিপশন) জন্য প্রস্তুত। Google সুপারিশ করে যে onCreateView-এ শুধু লেআউট ইনফ্লেট করুন, এবং সমস্ত UI কনফিগারেশন onViewCreated-এ করুন।
onDestroy — Fragment একটি অবজেক্ট হিসাবে নষ্ট হয় (ViewModel পরিষ্কার হয়, করুটিন বাতিল হয়)। onDetach শেষ কলব্যাক, যার পর Fragment Activity থেকে বিচ্ছিন্ন হয়। ব্যবহারিকভাবে সমস্ত সম্পদ onDestroyView (View) ও onDestroy (Fragment)-এ মুক্ত করা উচিত। onDetach Activity-র রেফারেন্স পরিষ্কার করার জন্য।
Fragment অদৃশ্য হয় যদি এটি BackStack-এ সংরক্ষণসহ লেনদেনের মাধ্যমে FragmentManager-এ যোগ করা না হয় বা যদি Activity onCreate-এ FragmentManager পুনরুদ্ধার না করে। সমাধান: onCreate-এ savedInstanceState == null পরীক্ষা সহ supportFragmentManager.beginTransaction().add()-এর মাধ্যমে প্রোগ্রামেটিকভাবে Fragment যোগ করুন।
না। Fragment সর্বদা FragmentManager-এর মাধ্যমে Activity-র সাথে যুক্ত। স্ক্রিন ঘোরানোর সময়ও, Activity পুনরায় তৈরি হয় এবং Fragment নতুন Activity-র সাথে পুনরায় সংযুক্ত হয়। Activity-র বাইরে Fragment তৈরি করা অসম্ভব — Fragment কন্সট্রাক্টরের সিস্টেম পুনরুদ্ধারের জন্য খালি কন্সট্রাক্টর প্রয়োজন।
নেস্টেড fragments হল অন্য Fragment-এর ভিতরে Fragments। জটিল স্ক্রিন তৈরিতে ব্যবহৃত হয়: ট্যাব প্যানেল, ট্যাবযুক্ত প্যানেল, মাস্টার-ডিটেল। নেস্টেড fragments চাইল্ড FragmentManager (childFragmentManager) দ্বারা পরিচালিত হয়। Google কর্মক্ষমতা সমস্যা এড়াতে 2 স্তরের বেশি নেস্টিং না করার সুপারিশ করে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন