Fragment Lifecycle: مبانی، متدهای onCreateView onViewCreated

نویسنده: IT Sectr منتشر شده: 2026-03-04 زمان مطالعه: 12 دقیقه

Fragment Lifecycle — توالی کاملاً مشخصی از متدهای بازخورد (callback) است که Android در طول عمر Fragment فراخوانی می‌کند: از ایجاد (onAttach) تا حذف کامل (onDetach). Fragment چرخه حیات پیچیده‌تری نسبت به Activity دارد — شامل 11 حالت و 7 بازخورد اصلی است. Fragment Lifecycle از طریق FragmentManager مدیریت می‌شود و با چرخه حیات Activity میزبان خود ارتباط تنگاتنگی دارد. طبق داده‌های Google، Fragment در 74% اپلیکیشن‌های Android که در API Level 21+ کار می‌کنند استفاده می‌شود که درک Fragment Lifecycle را برای توسعه‌حرفه‌ای Android ضروری می‌سازد. مستندات Android درباره Fragment Lifecycle تمام حالت‌ها و تضمین‌های فراخوانی را شرح می‌دهد.

نکات مهم

  • Fragment Lifecycle شامل 7 بازخورد است: onAttach، onCreate، onCreateView، onViewCreated، onStart، onResume، onPause، onStop، onDestroyView، onDestroy، onDetach.
  • FragmentManager وضعیت‌های Fragment را مدیریت می‌کند و ترتیب صحیح فراخوانی‌ها را در تراکنش‌ها تضمین می‌کند.
  • onCreateView و onViewCreated — متدهای کلیدی برای ایجاد و پیکربندی UI Fragment.
  • Fragment می‌تواند از Activity خود (در هنگام چرخش صفحه) جان سالم به در ببرد و وضعیت را از طریق onSaveInstanceState بازیابی کند.
  • viewLifecycleOwner — Lifecycle جداگانه برای View Fragment که در onDestroyView از بین می‌رود.

Fragment Lifecycle: مبانی چرخه حیات

Fragment Lifecycle مجموعه‌ای از حالت‌ها و متدهای به هم پیوسته است که هر نمونه Fragment از لحظه ایجاد تا نابودی از آن عبور می‌کند. برخلاف Activity، چرخه حیات Fragment به دو زمینه متصل است: خود Fragment (از onAttach تا onDetach زندگی می‌کند) و View آن (از onCreateView تا onDestroyView زندگی می‌کند). این تفکیک ویژگی کلیدی Fragment است که به آن اجازه می‌دهد نابودی View را در چرخش صفحه بدون نابودی خود Fragment تحمل کند.

توالی کامل بازخوردهای Fragment:

  • onAttach(Context) — Fragment به Activity متصل می‌شود. اولین بار فراخوانی می‌شود. Context — Activity میزبان.
  • onCreate(Bundle) — Fragment مقداردهی اولیه می‌شود. در اینجا ViewModel ایجاد می‌شود، آداپتورها پیکربندی می‌شوند.
  • onCreateView(LayoutInflater, ViewGroup, Bundle) — سلسله‌مراتب View Fragment ایجاد می‌شود. View ریشه را برمی‌گرداند.
  • onViewCreated(View, Bundle) — View ایجاد شد. در اینجا عناصر UI پیکربندی می‌شوند، اشتراک‌های LiveData تنظیم می‌شوند.
  • onStart() — Fragment قابل مشاهده است. انیمیشن‌ها شروع می‌شوند، سنسورها ثبت می‌شوند.
  • onResume() — Fragment فعال است، با کاربر تعامل دارد.
  • onPause() — Fragment فوکوس خود را از دست می‌دهد. انیمیشن‌ها متوقف می‌شوند.
  • onStop() — Fragment نامرئی است. منابع غیر بحرانی آزاد می‌شوند.
  • onDestroyView() — سلسله‌مراتب View نابود می‌شود. ارجاعات به View صفر می‌شوند.
  • onDestroy() — Fragment نابود می‌شود. کوروتین‌های خارج از viewModelScope لغو می‌شوند.
  • onDetach() — Fragment از Activity جدا می‌شود. پاکسازی نهایی.

به گفته Google، فرگمنت متوسط در یک اپلیکیشن مدرن 3–5 بار در هر جلسه کاربر چرخه کامل را طی می‌کند (به دلیل چرخش صفحه و ناوبری). پردازش صحیح همه فازها اساس پایداری UI است.

حالت‌های Fragment: از INITIALIZED تا DESTROYED

FragmentManager Fragment را از طریق پنج حالت اصلی مدیریت می‌کند که در کلاس Fragment.State تعریف شده‌اند. هر حالت با مجموعه مشخصی از بازخوردهای اجرا شده مطابقت دارد.

حالتمعنیبازخوردهای اجرا شده
INITIALIZEDFragment ایجاد شده، اما View هنوز وجود نداردonAttach, onCreate
CREATEDView ایجاد شده، اما Fragment قابل مشاهده نیست+ onCreateView, onViewCreated
STARTEDFragment قابل مشاهده، اما غیرفعال است+ onStart
RESUMEDFragment فعال است، با کاربر تعامل دارد+ onResume
DESTROYEDFragment نابود شده+ onDestroyView, onDestroy, onDetach

FragmentManager Fragment را بسته به اقدامات کاربر و رویدادهای سیستم بین حالت‌ها جابه‌جا می‌کند. هنگام افزودن Fragment به کانتینر، به ترتیب INITIALIZED → CREATED → STARTED → RESUMED را طی می‌کند. هنگام حذف — RESUMED → STARTED → CREATED → DESTROYED.

حالت CREATED — ویژه است: View ممکن است نابود شود (بعد از onDestroyView)، اما خود Fragment در حالت CREATED باقی می‌ماند (بعد از onDestroyView، قبل از onDestroy). این به FragmentManager اجازه می‌دهد Fragment را بدون View در حافظه نگه دارد که برای تحمل چرخش صفحه ضروری است.

تفاوت Fragment Lifecycle با Activity Lifecycle

Fragment Lifecycle و Activity Lifecycle ارتباط نزدیکی دارند اما تفاوت‌های اساسی دارند. Fragment همیشه درون Activity زندگی می‌کند و چرخه حیات آن به Activity میزبان وابسته است اما با آن یکسان نیست.

جنبهActivityFragment
تعداد بازخوردها7 (onCreate … onDestroy)11 (onAttach … onDetach)
Lifecycle جداگانه برای Viewخیربله (viewLifecycleOwner)
تحمل چرخشخیر (نابود می‌شود)بله (ViewModel + Fragment زنده می‌مانند)
وابستگی به میزبانخیروابسته به Activity Lifecycle
ذخیره وضعیتonSaveInstanceStateonSaveInstanceState (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: مدیریت حالت‌ها و تراکنش‌ها

FragmentManager — کلاس مرکزی مسئول افزودن، حذف، جایگزینی فرگمنت‌ها و مدیریت حالت‌های آنها. FragmentManager پشته BackStack را نگهداری می‌کند و ترتیب صحیح بازخوردها را در تراکنش‌ها تضمین می‌کند. هر Activity و هر Fragment تو در تو FragmentManager مخصوص خود را دارند.

عملیات اصلی FragmentManager:

  • beginTransaction() — یک تراکنش برای گروهی از عملیات باز می‌کند.
  • add() — Fragment را به کانتینر اضافه می‌کند. Fragment چرخه کامل lifecycle را تا RESUMED طی می‌کند.
  • replace() — Fragment فعلی را با جدید جایگزین می‌کند. برابر است با remove() + add().
  • remove() — Fragment را حذف می‌کند. Fragment lifecycle را از RESUMED تا DESTROYED طی می‌کند.
  • hide()/show() — Fragment را بدون نابودی View مخفی/نمایش می‌دهد. Fragment در hide به STARTED و در show دوباره به RESUMED می‌رود.
  • detach()/attach() — Fragment را جدا/متصل می‌کند. detach View را نابود می‌کند (onDestroyView)، attach دوباره ایجاد می‌کند (onCreateView).
  • addToBackStack() — تراکنش را برای ناوبری «بازگشت» به BackStack اضافه می‌کند.

BackStack — پشته تراکنش‌های FragmentManager. با فشردن دکمه سیستم «بازگشت»، آخرین تراکنش در BackStack برگردانده می‌شود (popBackStack()). Fragment حذف شده از طریق popBackStack بازیابی می‌شود. اگر BackStack خالی باشد، فشردن «بازگشت» Activity را پایان می‌دهد.

به گفته Google، 78% مشکلات با Fragment (تکرار، صفحه‌های خالی، IllegalStateException) به استفاده نادرست از FragmentManager مربوط می‌شود. قانون اصلی: تراکنش‌ها را از طریق commit() (ناهمزمان) یا commitNow() (همزمان) بسته به زمینه اجرا کنید. commit() ترتیب صحیح را در تراکنش‌های متعدد تضمین می‌کند.

ذخیره وضعیت Fragment: onSaveInstanceState

Fragment مکانیزم ذخیره وضعیت خود را از طریق onSaveInstanceState پشتیبانی می‌کند که مستقل از Activity کار می‌کند. Fragment وضعیت را در Bundle ذخیره می‌کند که هنگام بازیابی به onCreate و onCreateView منتقل می‌شود.

چه زمانی Fragment وضعیت را ذخیره می‌کند:

  • هنگام چرخش صفحه — View نابود می‌شود، Fragment وضعیت را در Bundle ذخیره می‌کند.
  • هنگام اتصال Fragment به Activity پس از process death.
  • هنگام فراخوانی onSaveInstanceState از Activity (سیستم ذخیره را به تمام فرگمنت‌های فرزند گسترش می‌دهد).

رویکرد مدرن: از SavedStateHandle در ViewModel برای ذخیره وضعیت Fragment استفاده کنید. SavedStateHandle به طور خودکار داده‌ها را در چرخش صفحه و process death ذخیره و بازیابی می‌کند، بدون نیاز به onSaveInstanceState دستی. Google SavedStateHandle را به عنوان روش ترجیحی برای ذخیره وضعیت UI در Fragment توصیه می‌کند.

setRetainInstance (از Fragment 1.3 منسوخ شده): قبلاً Fragment می‌توانست از طریق setRetainInstance(true) در چرخش صفحه حفظ شود. این رویکرد با ViewModel + SavedStateHandle جایگزین شده است که قابل‌اعتمادتر کار می‌کنند و نیاز به پیکربندی خاصی ندارند.

viewLifecycleOwner: چرخه حیات جداگانه View

viewLifecycleOwner — Lifecycle متصل به View Fragment (از onCreateView تا onDestroyView). این مفهوم اساساً مهم است: اشتراک‌های LiveData/Flow که از طریق viewLifecycleOwner انجام می‌شوند با نابودی View (onDestroyView) به طور خودکار لغو می‌شوند، اما روی خود Fragment تأثیر نمی‌گذارند.

تفاوت viewLifecycleOwner با lifecycle Fragment:

  • lifecycle (Fragment) — از onAttach تا onDetach زندگی می‌کند. اشتراک‌ها حتی پس از نابودی View فعال می‌مانند.
  • viewLifecycleOwner — از onCreateView تا onDestroyView زندگی می‌کند. اشتراک‌ها با نابودی View لغو می‌شوند.

چرا این مهم است: اگر از طریق lifecycle Fragment (this) در LiveData مشترک شوید، پس از onDestroyView اشتراک فعال می‌ماند و LiveData سعی می‌کند View null را به‌روزرسانی کند و باعث NPE می‌شود. اشتراک از طریق viewLifecycleOwner تضمین می‌کند که پس از onDestroyView هیچ به‌روزرسانی UI رخ ندهد.

قانون: در Fragment همیشه از viewLifecycleOwner برای اشتراک‌های LiveData، Flow و کوروتین‌های مرتبط با UI استفاده کنید. برای کوروتین‌های ViewModel از viewModelScope استفاده کنید — این به ViewModel متصل است، نه به Fragment.

نمونه کدهای Fragment در Kotlin

مثال 1: Fragment پایه با onViewCreated و viewLifecycleOwner

مقداردهی اولیه صحیح UI و اشتراک LiveData از طریق viewLifecycleOwner را نشان می‌دهد.

kotlin
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 layout را در onCreateView باد می‌کند، UI را پیکربندی می‌کند و در onViewCreated در LiveData مشترک می‌شود. اشتراک از طریق viewLifecycleOwner — یک الزام اجباری برای جلوگیری از نشت حافظه است. onDestroyView نابودی View را ثبت می‌کند — تأییدی که Fragment چرخش صفحه را تحمل می‌کند.

مثال 2: Fragment با FragmentManager و تراکنش‌ها

افزودن Fragment از طریق FragmentManager در Activity، جایگزینی با BackStack و بازیابی را نشان می‌دهد.

kotlin
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 از supportFragmentManager برای مدیریت فرگمنت‌ها استفاده می‌کند. تراکنش add() با BackStack تضمین می‌کند که با فشردن «بازگشت» HomeFragment بازیابی شود. openDetail() Fragment فعلی را با DetailFragment با آرگومان‌ها جایگزین می‌کند. بررسی savedInstanceState == null از تکرار فرگمنت‌ها در چرخش صفحه جلوگیری می‌کند.

مثال 3: Fragment با LifecycleObserver و StateFlow

استفاده از Flow و StateFlow در Fragment با viewLifecycleOwner برای به‌روزرسانی واکنش‌گرای UI.

kotlin
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 Binding برای دسترسی به View استفاده می‌کند. کوروتین viewLifecycleOwner.lifecycleScope.launch با نابودی View به طور خودکار لغو می‌شود. Binding برای جلوگیری از نشت در onDestroyView صفر می‌شود. StateFlow به‌روزرسانی داده‌ها را هنگام بازسازی View تضمین می‌کند.

سوالات متداول

onViewCreated چه تفاوتی با onCreateView دارد؟

onCreateView — View ریشه Fragment را ایجاد و برمی‌گرداند. onViewCreated — بلافاصله پس از ایجاد View فراخوانی می‌شود و تضمین می‌کند View کاملاً مقداردهی اولیه شده و برای پیکربندی آماده است (findViewById، اشتراک‌ها). Google توصیه می‌کند در onCreateView فقط layout را باد کنید و تمام پیکربندی UI را در onViewCreated انجام دهید.

Fragment چه زمانی واقعاً نابود می‌شود — onDestroy یا onDetach؟

onDestroy — Fragment به عنوان یک شی نابود شده است (ViewModel پاک می‌شود، کوروتین‌ها لغو می‌شوند). onDetach — آخرین بازخورد است که پس از آن Fragment از Activity جدا می‌شود. عملاً تمام منابع باید در onDestroyView (View) و onDestroy (Fragment) آزاد شوند. onDetach برای پاکسازی ارجاعات به Activity است.

چرا Fragment پس از چرخش صفحه ناپدید می‌شود؟

Fragment ناپدید می‌شود اگر از طریق تراکنش با ذخیره در BackStack به FragmentManager اضافه نشده باشد یا اگر Activity FragmentManager را در onCreate بازیابی نکند. راه‌حل: Fragment را به صورت برنامه‌نویسی از طریق supportFragmentManager.beginTransaction().add() در onCreate با بررسی savedInstanceState == null اضافه کنید.

آیا Fragment می‌تواند بدون Activity وجود داشته باشد؟

خیر. Fragment همیشه از طریق FragmentManager به Activity متصل است. حتی در چرخش صفحه Activity بازسازی می‌شود و Fragment دوباره به Activity جدید متصل می‌شود. ایجاد Fragment خارج از Activity غیرممکن است — سازنده Fragment برای بازیابی توسط سیستم به سازنده خالی نیاز دارد.

nested fragments چیست و چه کاربردی دارند؟

Nested fragments (فرگمنت‌های تو در تو) — Fragment درون Fragment دیگر. برای ساخت صفحه‌های پیچیده استفاده می‌شود: پنل‌های تب، پنل‌های زبانه‌ای، master-detail. فرگمنت‌های تو در تو توسط FragmentManager فرزند (childFragmentManager) مدیریت می‌شوند. Google توصیه می‌کند برای جلوگیری از مشکلات عملکرد، از 2 سطح تو در تو تجاوز نکنید.

خلاصه

  • Fragment Lifecycle شامل 11 بازخورد است: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume → onPause → onStop → onDestroyView → onDestroy → onDetach.
  • FragmentManager حالت‌های Fragment (INITIALIZED → CREATED → STARTED → RESUMED → DESTROYED) و BackStack تراکنش‌ها را مدیریت می‌کند.
  • Fragment چرخش صفحه را تحمل می‌کند — View نابود می‌شود (onDestroyView)، اما Fragment و ViewModel زنده می‌مانند.
  • viewLifecycleOwner — Lifecycle جداگانه برای View Fragment؛ برای اشتراک‌های LiveData و کوروتین‌های UI اجباری است.
  • ذخیره وضعیت Fragment — از طریق onSaveInstanceState یا SavedStateHandle در ViewModel.
  • تراکنش‌های Fragment از طریق FragmentManager با commit() (ناهمزمان) یا commitNow() (همزمان) اجرا می‌شوند.
  • همیشه binding و ارجاعات به View را در onDestroyView برای جلوگیری از نشت حافظه صفر کنید.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید