, ,

بررسی Retain API در Jetpack Compose: پر کردن شکاف میان remember و ViewModel

بررسی Retain API در Jetpack Compose: پر کردن شکاف میان remember و ViewModel

سلام. یکی از چالش‌های همیشگی در توسعه اپلیکیشن‌های اندروید، مدیریت Configuration Changes (مانند چرخش صفحه یا تغییر تم) است. در Jetpack Compose، ابزارهای مختلفی برای مدیریت State داریم، اما همیشه یک جای خالی احساس می‌شد؛ جایی که می‌خواستیم یک آبجکت سنگین یا غیرقابل سریال‌سازی (Non-serializable) را بدون استفاده از ViewModel در چرخش صفحه حفظ کنیم.

اخیراً گوگل Retain API را معرفی کرده است که دقیقاً برای همین منظور طراحی شده است. در این پست به بررسی این API جدید، تفاوت آن با ابزارهای قبلی و زمان مناسب برای استفاده از آن می‌پردازیم.

بیشتر بخوانید: بررسی Retain API در Jetpack Compose: پر کردن شکاف میان remember و ViewModel
retain - آموزش برنامه نویسی اندروید با jetpack compose

مشکل کجاست؟

در Compose، ما معمولاً از remember استفاده می‌کنیم. اما همانطور که می‌دانید، با چرخش صفحه (Activity Recreation)، مقادیر داخل remember پاک می‌شوند.

راهکار قبلی rememberSaveable است. این تابع عالی عمل می‌کند، اما دو محدودیت بزرگ دارد:

  1. محدودیت نوع داده: داده‌ها باید Serializable یا Parcelable باشن، داخل Bundle جا شوند .
  2. محدودیت حجم: برای ذخیره آبجکت‌های سنگین یا پیچیده مثل ExoPlayer، Bitmap یا کلاس‌های پیچیده‌ای که خودمان کنترلی روی سریال‌سازی آن‌ها نداریم، مناسب نیست.

راهکار جدید: retain

تابع retain دقیقاً در شکاف بین remember و ViewModel قرار می‌گیرد. این تابع به شما اجازه می‌دهد هر نوع آبجکتی (حتی آن‌هایی که سریال‌سازی نمی‌شوند) را در حافظه نگه دارید تا از چرخش صفحه جان سالم به در ببرند.

ویژگی‌های کلیدی retain:

  • بقا در چرخش صفحه: مقادیر با recreate شدن اکتیویتی از بین نمی‌روند.
  • حفظ نمونه اصلی (Instance): برخلاف rememberSaveable که آبجکت را بازسازی می‌کند، retain دقیقاً همان نمونه (Reference) قبلی را نگه می‌دارد.
  • بدون نیاز به سریال‌سازی: می‌توانید هر چیزی، از یک Listener ساده تا یک نمونه سنگین Video Player را در آن نگه دارید.

مثال کاربردی: مدیا پلیر

تصور کنید می‌خواهید یک ExoPlayer را در یک Composable بسازید. اگر از remember استفاده کنید، با هر چرخش صفحه پلیر دوباره ساخته شده و پخش ویدیو قطع می‌شود. rememberSaveable هم کار نمی‌کند چون ExoPlayer قابل سریال‌سازی نیست. اینجا retain می‌درخشد:

Kotlin

@Composable
fun VideoPlayer() {
    val context = LocalContext.current.applicationContext
    
    // این آبجکت در چرخش صفحه حفظ می‌شود
    val exoPlayer = retain {
        ExoPlayer.Builder(context).build()
    }
    
    // استفاده از پلیر در UI...
}

مفهوم جدید: RetainedEffect

همراه با این API، مفهومی شبیه به DisposableEffect داریم که رفتار هوشمندانه‌تری دارد. اگر شما نیاز دارید وقتی Composable “واقعاً” از صفحه حذف شد (نه فقط موقع چرخش صفحه) منابعی را آزاد کنید، باید از مکانیزم پاک‌سازی retain استفاده کنید.

در retain، برخلاف DisposableEffect، کد پاک‌سازی (Cleanup) هنگام چرخش صفحه اجرا نمی‌شود. تنها زمانی اجرا می‌شود که آن Composable برای همیشه از ساختار UI (Hierarchy) حذف شود.

مقایسه: retain در برابر ViewModel

شاید بپرسید “چرا از همان ViewModel استفاده نکنیم؟”

داکیومنت‌های اندروید تأکید می‌کنند که retain جایگزین ViewModel نیست.

ویژگیretainViewModel
طول عمر (Scope)محدود به یک Composable خاص (Positional)محدود به صفحه (Screen) یا Navigation Graph
هدف اصلیمنطق UI، کش‌های داخلی، اشیاء سنگین (UI Plumbing)منطق بیزنس (Business Logic)، مدیریت State صفحه
وابستگیمستقل، بدون نیاز به Hilt/Daggerمعمولاً با Hilt و SavedStateHandle ترکیب می‌شود
بقا در Process Death❌ خیر (اگر سیستم اپ را بکشد، دیتا می‌پرد)✅ بله (اگر با SavedStateHandle ترکیب شود)

چه زمانی از چی استفاده کنیم؟

  1. از remember استفاده کنید: برای Stateهای ساده و موقتی که با چرخش صفحه مهم نیست اگر ریست شوند (مثل انیمیشن‌های لحظه‌ای).
  2. از rememberSaveable استفاده کنید: برای ذخیره ورودی کاربر (تکس‌باکس‌ها)، موقعیت اسکرول و Stateهای کوچکی که باید حتی اگر پروسه اپ کشته شد، باقی بمانند.
  3. از ViewModel استفاده کنید: برای مدیریت کلی دیتای صفحه، ارتباط با دیتابیس/سرور و منطق‌های پیچیده.
  4. از retain استفاده کنید:
    • زمانی که نیاز دارید یک آبجکت سنگین یا پیچیده (مثل Video Player، Socket Connection، Image Loader) را فقط در یک Composable خاص نگه دارید.
    • زمانی که می‌خواهید یک کامپوننت Reusable بسازید که state داخلی خودش را مدیریت کند و نمی‌خواهید خود را مجبور به ساخت ViewModel کنید.

جمع‌بندی

قابلیت retain ابزاری قدرتمند برای نویسندگان کتابخانه‌ها (Library Authors) و توسعه‌دهندگانی است که کامپوننت‌های پیشرفته UI می‌سازند. این API مدیریت منابع را در چرخش صفحه بسیار ساده می‌کند، اما باید مراقب بود که از آن به عنوان جایگزینی برای معماری استاندارد MVVM استفاده نشود.

برای توضیحات بیشتر، این ویدیو از فیلیپ می تونه خیلی مفید باشه.

Comments

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *