Fragment Lifecycle کال بیک طریقوں کا سختی سے متعین کردہ ایک سلسلہ ہے جسے Android Fragment کی زندگی بھر میں کال کرتا ہے: تشکیل (onAttach) سے مکمل ہٹانے (onDetach) تک۔ Fragment کا لائف سائیکل Activity سے زیادہ پیچیدہ ہے — اس میں 11 حالتیں اور 7 اہم کال بیک شامل ہیں۔ Fragment Lifecycle کا نظم FragmentManager کے ذریعے کیا جاتا ہے اور یہ اسے رکھنے والی Activity کے لائف سائیکل سے قریبی تعلق رکھتا ہے۔ Google کے مطابق، Fragment API Level 21+ پر چلنے والی Android ایپلیکیشنز کے 74% میں استعمال ہوتا ہے، جس سے پیشہ ورانہ 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 اور ہر nested Fragment کا اپنا FragmentManager ہوتا ہے۔
FragmentManager کے اہم عمل:
BackStack FragmentManager کا لین دین کا ڈھیر ہے۔ سسٹم Back بٹن دبانے پر، BackStack میں آخری لین دین واپس لے لیا جاتا ہے (popBackStack())۔ popBackStack کے ذریعے ہٹایا گیا Fragment بحال ہو جاتا ہے۔ اگر BackStack خالی ہے، تو Back دبانے سے Activity ختم ہو جاتی ہے۔
Google کے مطابق، Fragment کے مسائل (نقل، خالی اسکرینیں، IllegalStateException) کا 78% 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 ایک Lifecycle ہے جو Fragment View سے منسلک ہے (onCreateView سے onDestroyView تک)۔ یہ ایک بنیادی طور پر اہم تصور ہے: viewLifecycleOwner کے ذریعے LiveData/Flow پر کی گئی سبسکرپشنز View تباہ ہونے (onDestroyView) پر خود بخود منسوخ ہو جاتی ہیں، لیکن خود Fragment کو متاثر نہیں کرتیں۔
viewLifecycleOwner اور Fragment lifecycle کے درمیان فرق:
یہ کیوں اہم ہے: اگر آپ Fragment lifecycle (this) کے ذریعے LiveData پر سبسکرائب کرتے ہیں، تو onDestroyView کے بعد سبسکرپشن فعال رہتی ہے اور LiveData ایک null 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 میں لے آؤٹ انفلیٹ کرتا ہے، onViewCreated میں UI ترتیب دیتا ہے اور 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 کو null کیا جاتا ہے۔ 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 کنسٹرکٹر کو نظام کی بحالی کے لیے خالی کنسٹرکٹر کی ضرورت ہوتی ہے۔
Nested fragments دوسرے Fragment کے اندر Fragments ہیں۔ پیچیدہ اسکرینیں بنانے کے لیے استعمال ہوتے ہیں: ٹیب پینلز، ٹیب والے پینلز، master-detail۔ Nested fragments کا نظم چائلڈ FragmentManager (childFragmentManager) کرتا ہے۔ Google کارکردگی کے مسائل سے بچنے کے لیے 2 سطحوں سے زیادہ نیسٹنگ نہ کرنے کی تجویز کرتا ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں