مدیریت دکمه بازگشت در Android: ماهیت، مکانیزم‌ها و پیاده‌سازی

نویسنده: IT Sectr منتشر شده: 2026-06-10 زمان مطالعه: 9 دقیقه

Back Press Handling — مکانیزم رهگیری و پردازش دکمه سیستمی «بازگشت» در Android است که تعیین می‌کند با فشار دادن آن چه عملی انجام شود. بر اساس Android Developers (2024)، از Android 11 به بعد متد سنتی onBackPressed() با OnBackPressedDispatcher جایگزین شده است. API جدید به مؤلفه‌ها در هر سطحی از سلسله‌مراتب امکان رهگیری فشار را می‌دهد، نه فقط Activity. تفاوت کلیدی — پشتیبانی از چندین callback در زنجیره با اولویت‌ها.

نکات اصلی

  • Back Press Handling — مکانیزم پردازش دکمه سیستمی «بازگشت» در Android
  • OnBackPressedDispatcher — API جدید که جایگزین onBackPressed() منسوخ شده است
  • Callback با اولویت ثبت می‌شوند و به ترتیب زنجیره اجرا می‌شوند
  • Jetpack Compose از BackHandler برای رهگیری فشار در composable استفاده می‌کند
  • Support Library سازگاری معکوس تا API Level 14 را فراهم می‌کند

مدیریت دکمه بازگشت چیست

Back Press Handling — مکانیزم سیستمی Android است که تعیین می‌کند وقتی کاربر دکمه سخت‌افزاری یا نرم‌افزاری «بازگشت» را فشار می‌دهد چه اتفاقی می‌افتد. بسته به زمینه، فشار می‌تواند: صفحه فعلی را ببندد و به صفحه قبلی برگردد، صفحه‌کلید را مخفی کند، Drawer یا Bottom Sheet را ببندد، اگر کاربر در صفحه ریشه است از برنامه خارج شود.

رفتار دکمه «بازگشت» با هر نسخه Android تکامل یافته است. در Android 10 ژست‌های ناوبری ظاهر شدند، در Android 11 — OnBackPressedDispatcher به عنوان API استاندارد، و در Android 13 — پشتیبانی بهبودیافته predictive back gesture، که در آن سیستم قبل از اجرای واقعی عمل، انیمیشن انتقال را نشان می‌دهد. Google به طور مداوم به سمت رفتار قابل پیش‌بینی و سازگار Back Press در همه دستگاه‌ها حرکت می‌کند.

پردازش صحیح دکمه «بازگشت» — عنصر حیاتی UX در برنامه Android است. کاربر انتظار دارد که فشار «بازگشت» او را به صفحه قبلی در پشته ناوبری برگرداند، نه اینکه برنامه را به طور غیرمنتظره ببندد. نقض این انتظار یکی از دلایل اصلی نظرات منفی و رتبه‌های پایین در Google Play است.

تکامل Back Press API: از onBackPressed تا OnBackPressedDispatcher

تاریخچه Back Press API در Android تکامل کلی پلتفرم را منعکس می‌کند: از یک متد ساده در Activity تا یک سیستم callback منعطف با پشتیبانی از lifecycle و Compose. بیایید سه مرحله توسعه را بررسی کنیم.

دوران onBackPressed (API Level 1–30)

از اولین Android API، دکمه «بازگشت» در متد onBackPressed کلاس Activity پردازش می‌شد. توسعه‌دهنده این متد را override می‌کرد و منطق خود را می‌نوشت. مشکل این بود که Fragment و View نمی‌توانستند فشار را رهگیری کنند — تمام کنترل از طریق Activity انجام می‌شد. این منجر به Activity‌های حجیم و زنجیره if-else پیچیده برای تعیین اینکه چه کسی باید فشار را پردازش کند، می‌شد.

ظهور OnBackPressedDispatcher (Activity 1.0.0)

با Activity 1.0.0 (AndroidX) Google OnBackPressedDispatcher را معرفی کرد. این یک توزیع‌کننده مرکزی است که callback را از هر مؤلفه‌ای — Activity، Fragment، Dialog، View سفارشی — دریافت می‌کند. Callback‌ها با تعیین ترتیب (از طریق priority) ثبت می‌شوند و می‌توانند به صورت پویا اضافه یا حذف شوند. OnBackPressedDispatcher زودتر از onBackPressed قدیمی فراخوانی می‌شود که امکان رهگیری فشار را قبل از پردازش آن توسط Activity فراهم می‌کند.

Predictive Back Gesture (Android 13+)

Android 13 predictive back gesture را معرفی کرد — انیمیشن سیستمی که نشان می‌دهد فشار «بازگشت» به کجا منتهی می‌شود، حتی قبل از اینکه کاربر ژست را کامل کند. برای پشتیبانی از این انیمیشن، توسعه‌دهندگان باید از OnBackPressedDispatcher استفاده کنند و مشخص کنند که آیا callback از انیمیشن سیستمی از طریق ویژگی isEnabled پشتیبانی می‌کند یا خیر. اگر callback از predictive animation پشتیبانی نکند، سیستم انیمیشن پیش‌فرضی را نشان می‌دهد که ممکن است با زمینه برنامه مطابقت نداشته باشد.

APIحداقل SDKپشتیبانی FragmentPredictive Back
onBackPressedAPI Level 1از طریق Activityخیر
OnBackPressedDispatcherActivity 1.0.0مستقیمجزئی
OnBackPressedDispatcher + lifecycleActivity 1.3.0Lifecycle-awareکامل

OnBackPressedDispatcher — معماری و زنجیره callback

OnBackPressedDispatcher — هسته جدید Back Press API است. این زنجیره callback را مدیریت می‌کند و آنها را به ترتیب تا اولین callback که رویداد را پردازش می‌کند فراخوانی می‌کند. اگر هیچ callbackی فشار را پردازش نکند، توزیع‌کننده عمل پیش‌فرض را انجام می‌دهد — فراخوانی finish() برای Activity یا popBackStack() برای Navigation Component.

ثبت callback با اولویت

Callback از طریق addCallback با مشخص کردن LifecycleOwner و شی OnBackPressedCallback ثبت می‌شود. Callback شامل ویژگی isEnabled است — اگر false باشد، callback نادیده گرفته می‌شود. برای priority می‌توان مقداری از 0 (پایین‌ترین) تا Integer.MAX_VALUE ارسال کرد. Fragment Activity Result API از این مکانیزم برای ثبت خودکار callback متصل به چرخه حیات استفاده می‌کند.

kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val callback = object : OnBackPressedCallback(enabled = true) {
        override fun handleOnBackPressed() {
            if (isDrawerOpen) { closeDrawer() }
            else { isEnabled = false; onBackPressed() }
        }
    }
    onBackPressedDispatcher.addCallback(this, callback)
}

پاکسازی Lifecycle-aware

Callback به طور خودکار حذف می‌شود وقتی LifecycleOwner به حالت DESTROYED می‌رود. این مشکل قدیمی نشت callback در هنگام چرخش صفحه را حل می‌کند. اگر callback به Fragment اضافه شده باشد، تضمین می‌شود که هنگام نابودی Fragment حذف شود. برای غیرفعال کردن موقت callback از ویژگی isEnabled استفاده می‌شود — می‌توان آن را بدون حذف و ثبت مجدد تغییر داد.

زنجیره فراخوانی

ترتیب فراخوانی معکوس ترتیب اضافه شدن است: آخرین callback اضافه شده ابتدا کنترل را دریافت می‌کند. این منطقی است زیرا تو در توترین عنصر UI (مثلاً Bottom Sheet داخل Fragment) باید فشار را زودتر از Fragment والد پردازش کند. اگر عمیق‌ترین callback فشار را پردازش نکند (isEnabled = false)، کنترل به بعدی در زنجیره منتقل می‌شود.

Back Press در Fragment و دیالوگ‌ها

Fragment API یکپارچگی خاص خود را با OnBackPressedDispatcher از طریق متد requireActivity().onBackPressedDispatcher فراهم می‌کند. از Fragment 1.2.0 به بعد، هر Fragment می‌تواند callback خود را ثبت کند که به طور خودکار به چرخه حیات Fragment متصل شده و هنگام نابودی آن حذف می‌شود.

Callback در Fragment

ثبت callback در Fragment در onCreate، onViewCreated یا حتی در خود View انجام می‌شود — فقط مهم است که LifecycleOwner (Fragment) فعال باشد. وقتی Fragment به حالت STARTED می‌رود، callback فعال می‌شود، در STOPPED — غیرفعال می‌شود. این تضمین می‌کند که Fragment مخفی (در ViewPager) فشار «بازگشت» را پردازش نکند.

kotlin
class EditorFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val callback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                showDiscardDialog()
            }
        }
        requireActivity().onBackPressedDispatcher.addCallback(this, callback)
    }
}

Dialog و BottomSheetDialog

دیالوگ‌ها و BottomSheet به طور خودکار فشار «بازگشت» را برای بسته شدن رهگیری می‌کنند. اگر نیاز به انجام اقدام اضافی قبل از بسته شدن دارید — callback را با اولویت بالاتر ثبت کنید. مهم: اگر setCancelable(false) را روی Dialog تنظیم کرده باشید، callback کار نخواهد کرد — این رفتار سیستمی است.

مدیریت دکمه بازگشت در Jetpack Compose

Jetpack Compose API اعلامی برای پردازش دکمه «بازگشت» از طریق تابع composable BackHandler فراهم می‌کند. BackHandler شامل enabled (مقدار بولی) و onBack — callback که هنگام فشار فراخوانی می‌شود. اگر enabled = false باشد، فشار در طول زنجیره به جلو منتقل می‌شود.

BackHandler در Compose

BackHandler به طور خودکار OnBackPressedCallback را در OnBackPressedDispatcher Activity والد ثبت می‌کند. این چرخه حیات composable را در نظر می‌گیرد: هنگام خروج از ترکیب، callback حذف می‌شود. enabled می‌تواند به حالت متصل شود — مثلاً فقط در صورت وجود تغییرات ذخیره‌نشده در فرم، دیالوگ تأیید را نشان دهد.

kotlin
@Composable
fun EditScreen(hasUnsavedChanges: Boolean) {
    BackHandler(enabled = hasUnsavedChanges) {
        // نمایش دیالوگ تأیید
    }

    Column {
        TextField(value = ..., onValueChange = ...)
    }
}

Predictive Back در Compose

Predictive back gesture در Compose از Compose 1.5.0 پشتیبانی می‌شود. BackHandler اگر روی دستگاه فعال باشد، به طور خودکار انیمیشن انتقال سیستمی را مدیریت می‌کند. برای predictive-animation سفارشی از تغییردهنده predictiveBackHandler استفاده کنید که پیشرفت ژست را از 0 تا 1 برمی‌گرداند.

اشتباهات رایج و best practices

Back Press Handling ساده به نظر می‌رسد، اما در عمل توسعه‌دهندگان مرتکب اشتباهات سیستماتیکی می‌شوند. بیایید رایج‌ترین مشکلات و راه‌حل‌های آنها را بر اساس توصیه‌های Google و تجربه جامعه بررسی کنیم.

اشتباه: فراخوانی finish() بدون بررسی پشته ناوبری

فراخوانی مستقیم finish() در handleOnBackPressed می‌تواند منجر به خروج غیرمنتظره از برنامه شود اگر در پشته ناوبری صفحات پس‌زمینه وجود داشته باشد. همیشه قبل از بستن Activity، NavController.backStack را از طریق Navigation Component یا Coordinator بررسی کنید.

اشتباه: نادیده گرفتن lifecycle هنگام ثبت callback

اگر callback را بدون LifecycleOwner (با استفاده از addCallback قدیمی بدون پارامتر) ثبت کنید، callback برای همیشه زنده می‌ماند و ممکن است اگر Activity قبلاً نابود شده باشد NullPointerException ایجاد کند. همیشه از addCallback(this, callback) با LifecycleOwner استفاده کنید.

Best Practice: قطع زنجیره برای پنجره‌های مدال

برای پنجره‌های مدال (Bottom Sheet, Dialog) همیشه isEnabled = true را فقط زمانی تنظیم کنید که پنجره قابل مشاهده است. از addCallback با لامبدا که وضعیت پنجره را بررسی می‌کند استفاده کنید. Navigation Component این را به طور خودکار برای NavHost مدیریت می‌کند.

Best Practice: پردازش فشار دوبل

فشار سریع دوبل «بازگشت» می‌تواند منجر به فراخوانی دوبل finish() شود. از flag یا throttleLast برای محافظت در برابر فراخوانی‌های مکرر در عرض 500 میلی‌ثانیه استفاده کنید. Navigation Component این وضعیت را به صورت داخلی مدیریت می‌کند، اما در سناریوهای سفارشی باید حفاظت را به صورت دستی پیاده‌سازی کرد.

kotlin
private var lastBackPressTime = 0L

override fun handleOnBackPressed() {
    val currentTime = System.currentTimeMillis()
    if (currentTime - lastBackPressTime > 500) {
        lastBackPressTime = currentTime
        navigateBack()
    }
}

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

چرا onBackPressed منسوخ شد؟

onBackPressed در Android 11 منسوخ شد زیرا فقط در سطح Activity کار می‌کند. OnBackPressedDispatcher به هر مؤلفه‌ای (Fragment, Dialog, View) اجازه می‌دهد فشار را از طریق یک مکانیزم واحد با پشتیبانی از چرخه حیات رهگیری کند.

چگونه فشار «بازگشت» را از ژست سوایپ تشخیص دهیم؟

سیستم Android ژست سوایپ از لبه را قبل از دریافت آن توسط برنامه به فشار سیستمی «بازگشت» تبدیل می‌کند. در سطح OnBackPressedDispatcher نمی‌توانید این دو رویداد را تشخیص دهید — هر دو به صورت handleOnBackPressed می‌رسند.

آیا باید دکمه «بازگشت» را در دستگاه‌های دارای ژست پشتیبانی کرد؟

بله، پردازش OnBackPressedDispatcher برای دستگاه‌های دارای سه دکمه و ناوبری ژستی یکسان است. کد رهگیری به نوع ناوبری بستگی ندارد — سیستم خود ژست را به فراخوانی توزیع‌کننده تبدیل می‌کند.

چگونه predictive back gesture را در شبیه‌ساز测试 کنیم؟

فعال کنید predictive back را در Developer Options شبیه‌ساز Android 13+. از ADB استفاده کنید: `adb shell settings put global enable_back_animation 1`. پس از فعال‌سازی، انیمیشن سیستمی پیش‌نمایش انتقال را هنگام فشار «بازگشت» نشان می‌دهد.

اگر callback فراخوانی نشد چه باید کرد؟

دو شرط را بررسی کنید: LifecycleOwner باید در حالت STARTED یا RESUMED باشد و isEnabled callback باید true باشد. اگر هر دو شرط برآورده شده‌اند، مطمئن شوید که callback به OnBackPressedDispatcher صحیح اضافه شده است — در Fragment از requireActivity().onBackPressedDispatcher استفاده کنید.

خلاصه

  • Back Press Handling — مکانیزم پردازش دکمه سیستمی «بازگشت» در Android
  • OnBackPressedDispatcher — API مدرن که از Android 11 جایگزین onBackPressed() شده است
  • Callback از طریق addCallback با LifecycleOwner ثبت می‌شوند و به طور خودکار پاک می‌شوند
  • زنجیره فراخوانی — آخرین callback اضافه شده با isEnabled=true اولین بار فشار را پردازش می‌کند
  • در Fragment callback به چرخه حیات متصل می‌شود و هنگام مخفی شدن غیرفعال می‌شود
  • Jetpack Compose از BackHandler composable برای پردازش اعلامی استفاده می‌کند
  • Predictive back gesture — انیمیشن انتقال سیستمی، قابل دسترس از Android 13+

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

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

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

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