محمد صادق مهرافزون
محمد صادق مهرافزون
خواندن ۶ دقیقه·۵ ساعت پیش

تکنیک‌های بهینه‌سازی در Jetpack Compose

در توسعه اپلیکیشن‌های Android با استفاده از Jetpack Compose، بهینه‌سازی عملکرد برای ارائه تجربه کاربری روان و سریع بسیار مهم است. بهینه‌سازی درست می‌تواند باعث کاهش مصرف حافظه، کاهش زمان رندر و کاهش Recomposition های غیرضروری شود، که در این پست به بررسی چند مورد میپردازیم.

1. به حداقل رساندن Recomposition
بازترکیب (Recomposition) فرآیندی است که Jetpack Compose برای به‌روزرسانی رابط کاربری انجام می‌دهد و با تغییر وضعیت‌ها (State) ایجاد می‌شود. اگرچه این فرآیند کارآمد است، اما Recomposition های غیرضروری می‌توانند عملکرد را کند کنند. برای مدیریت بهتر Recomposition ها، این نکات را در نظر بگیرید:

  • محدود کردن محدوده State به جایی که نیاز است:
    متغیرهای State را فقط در همان کامپوزهایی که به آنها نیاز دارند نگه دارید. این کار تأثیر تغییر State را روی دیگر عناصر رابط کاربری کاهش می‌دهد.

به بیان دیگر به این معناست که متغیرهایی که وضعیت (State) را ذخیره می‌کنند، فقط در همان بخشی از رابط کاربری که مستقیماً به آن‌ها نیاز دارد استفاده شوند، نه در کل برنامه یا کامپوزهای دیگر.

مثال ساده:

فرض کنید شما یک اپلیکیشن دارید که یک تعداد کلیک (Click Counter) را نشان می‌دهد. رابط کاربری شامل دو بخش است:

  1. بخش شمارش کلیک‌ها که عدد کلیک را نشان می‌دهد.
  2. بخش توضیحات که یک متن ثابت مثلاً "روی دکمه کلیک کنید" نمایش می‌دهد.

اگر متغیر State (مثل clickCount) را در سطح بالای کل اپلیکیشن نگه دارید، هر بار که کاربر روی دکمه کلیک می‌کند و عدد کلیک تغییر می‌کند، هم بخش شمارش و هم بخش توضیحات Recomposition می‌شوند، حتی اگر بخش توضیحات نیازی به تغییر نداشته باشد.

راه‌حل: محدود کردن State به بخش مرتبط

متغیر clickCount را فقط در همان بخشی که عدد کلیک نمایش داده می‌شود (بخش شمارش کلیک‌ها) نگه دارید. این کار باعث می‌شود تغییر عدد کلیک فقط روی همان بخش تأثیر بگذارد و بخش توضیحات نیازی به Recomposition نداشته باشد.

  • استفاده از remember برای مقادیر کش‌شده:
    تابع remember مقادیر را در حافظه نگه می‌دارد و آنها را در Recomposition های بعدی مجدداً محاسبه نمی‌کند. این روش از محاسبات غیرضروری جلوگیری می‌کند.
  • استفاده از ساختارهای داده‌ای پایدار (Stable):
  • ارسال داده‌های پایدار که با annotations مانند Immutable@ یا Stable@ مشخص شده‌اند، به Jetpack Compose اعلام می‌کند که این مقادیر تغییر نخواهند کرد. این کار باعث کاهش Recomposition های غیرضروری می‌شود و عملکرد رابط کاربری را بهبود می‌بخشد.


۲. اجتناب از عملیات سنگین داخل کامپوزها

کامپوزها باید تنها مسئول مدیریت و نمایش رابط کاربری باشند، نه انجام محاسبات سنگین. برای اینکه رابط کاربری روان و واکنش‌پذیر باقی بماند، عملیات‌های سنگین را در پس‌زمینه انجام دهید:

  • اجرای وظایف سنگین با استفاده از Coroutine‌ها:
    برای کارهایی مانند دریافت داده از سرور یا انجام محاسبات پیچیده، از Coroutine‌ها استفاده کنید. این کار را می‌توانید داخل LaunchedEffect یا rememberCoroutineScope انجام دهید.


۳. استفاده از کامپوزهای Lazy برای لیست‌ها

هنگام نمایش لیست‌های طولانی، از کامپوزهای LazyColumn، LazyRow، یا LazyGrid استفاده کنید. این کامپوزها فقط آیتم‌های قابل مشاهده در صفحه را رندر می‌کنند و به این ترتیب باعث صرفه‌جویی در حافظه و زمان پردازش می‌شوند.


۴. استفاده مؤثر از Modifier API

این Modifiers ابزارهای قدرتمندی در Jetpack Compose برای مدیریت چیدمان و استایل‌دهی هستند. اما استفاده نادرست و غیربهینه از آنها می‌تواند عملکرد برنامه را کاهش دهد.

  • کاهش زنجیره‌های Modifier:
  • ترکیب بیش‌ازحد از Modifiers باعث پیچیدگی و کاهش عملکرد می‌شود. سعی کنید Modifiers مرتبط را گروه‌بندی کنید یا به‌طور منطقی ترکیب کنید.
  • قرار دادن Modifiers مشترک خارج از Composable@:
  • وقتی Modifierها را داخل یک تابع Composable@ تعریف کنید، در هر Recomposition دوباره محاسبه می‌شوند. برای جلوگیری از این مشکل، Modifierهایی که تغییر نمی‌کنند را خارج از تابع تعریف کنید.

مثال:

مشکل (استفاده غیربهینه):

  • مشکل:
    در این مثال، زنجیره طولانی از Modifiers باعث پیچیدگی شده است و اگر تابع Recomposition شود، همه این Modifierها دوباره محاسبه می‌شوند.

راه‌حل (استفاده بهینه):

مزایا:

  • وقتی Modifier‌ های مشترک تنها یک‌بار تعریف می‌شوند و بازترکیب روی آنها تأثیر نمی‌گذارد.
  • کد خواناتر و مدیریت آسان‌تر می‌شود.


۵. استفاده از derivedStateOf برای مدیریت کارآمد State های محاسبه‌شده

تابع derivedStateOf ابزاری مفید برای مدیریت کارآمد State های محاسبه‌شده است. این تابع به شما کمک می‌کند که داده‌های وابسته به تغییرات State دیگر را به صورت بهینه محاسبه کنید و از Recomposition های غیرضروری جلوگیری کنید.

توضیح:

وقتی وضعیت (State) در برنامه تغییر می‌کند، ممکن است بخواهید State های جدیدی را از آن استخراج کنید. به‌طور معمول، هر بار که State تغییر می‌کند، باید محاسبات جدید انجام شود. استفاده از derivedStateOf باعث می‌شود که فقط زمانی State محاسبه‌شده دوباره به‌روز شود که واقعاً نیاز باشد، و این می‌تواند عملکرد را بهبود دهد.

مثال :

فرض کنید یک برنامه دارید که دو عدد را دریافت می‌کند و حاصل جمع آنها را نمایش می‌دهد. هر بار که یکی از اعداد تغییر کند، باید حاصل جمع به‌روز شود.

استفاده از derivedStateOf:

توضیح کد:

  • تابعderivedStateOf فقط زمانی محاسبه می‌شود که یکی از مقادیر number1 یا number2 تغییر کند.
  • اگر هیچ‌کدام از این مقادیر تغییر نکنند، sum دوباره محاسبه نخواهد شد، حتی اگر سایر قسمت‌های رابط کاربری Recomposition شوند.


۶. پروفایل و بررسی چیدمان‌های خود با استفاده از Layout Inspector

از Layout Inspector در Android Studio برای نظارت بر چیدمان‌های Jetpack Compose خود استفاده کنید، تعداد Recomposition ها را مشاهده کنید و مشکلات عملکردی احتمالی را شناسایی کنید.

چگونه از Layout Inspector استفاده کنیم؟

۱. باز کردن Layout Inspector:

  • از منوی Tools در Android Studio گزینه Layout Inspector را انتخاب کنید.
  • این ابزار به شما امکان می‌دهد تا چیدمان‌های فعلی در اپلیکیشن خود را مشاهده و بررسی کنید.

۲. مشاهده تعداد Recomposition ها:

  • در پنل Layout Inspector، گزینه Show Recomposition Counts را فعال کنید.
  • این ویژگی به شما نشان می‌دهد که هر کامپوزابل چند بار Recomposition شده است.
  • با بررسی تعداد Recomposition ها می‌توانید تشخیص دهید کدام بخش‌های رابط کاربری بیش از حد Recomposition می‌شوند و نیاز به بهینه‌سازی دارند.


۷. استفاده از داده‌های غیرقابل تغییر برای محتوای ثابت

هنگام کار با داده‌های ثابت یا غیرقابل تغییر، از MutableState استفاده نکنید. برای محتوای ثابت، از متغیرهای معمولی یا remember بدون استفاده از MutableState استفاده کنید تا از اضافه‌بار حافظه جلوگیری کنید.

توضیح بیشتر:

داده‌هایی که تغییر نمی‌کنند (مثل متون ثابت، تصاویر پیش‌فرض، یا دیگر محتواهایی که همیشه یکسان هستند) نباید از MutableState استفاده کنند. MutableState برای وضعیت‌هایی است که نیاز به تغییر دارند، بنابراین استفاده از آن برای داده‌های ثابت تنها باعث مصرف بیشتر حافظه می‌شود و بهینه نیست. برای اینگونه داده‌ها، استفاده از متغیرهای ساده یا remember کافی است.

مثال :

استفاده نادرست (با MutableState):

  • مشکل:
    در این مثال، برای محتوای ثابت MutableState استفاده شده است، که باعث می‌شود Jetpack Compose به طور غیرضروری حافظه بیشتری مصرف کند و هر بار که کامپوز قابل Recomposition می‌شود، مقدار جدید محاسبه شود، حتی اگر محتوای آن تغییر نکند.

راه‌حل (استفاده از متغیر معمولی یا remember بدون MutableState):

مزایا:

  • در این روش، staticText فقط یک‌بار در حافظه ذخیره می‌شود و تنها در صورت نیاز به رندر مجدد، بدون محاسبه دوباره، استفاده می‌شود.
  • حافظه کمتری مصرف می‌شود و عملکرد بهبود می‌یابد، زیرا برای محتوای ثابت نیازی به مدیریت وضعیت نیست.


نتیجه گیری:

با پیروی از این روش‌ها، هم عملکرد و هم تجربه کاربری اپلیکیشن‌های Jetpack Compose شما بهبود خواهد یافت.


ممنون که تا آخر این پست همراه من بودید ، امیدوارم براتون مفید بوده باشه 🙌🙏✌ (:

بقیه آموزش های من با نام (mister developer) را می توانید در تلگرام و اینستاگرام دنبال کنید!!

کانال تلگرام: mister_developerr

اینستاگرام: mister_developerr

موفق و پیروز باشید


jetpack composeکاتلینبرنامه نویسیبرنامه نویسی اندرویدandroid development
شاید از این پست‌ها خوشتان بیاید