بهینه‌سازی تصاویر بیت‌مپ

اگر دقت نکنید، کار کردن با تصاویر می‌تواند به‌سرعت باعث بروز مشکلات عملکردی شود. حتی یک گرافیک کوچک در قالب فشرده مانند JPG یا PNG می‌تواند هنگام رمزگشایی برای نمایش به یک نقشه بیتی بزرگ تبدیل شود. اگر در نحوه استفاده از گرافیک کارآمد نباشید، ممکن است با مشکلات حافظه مواجه شوید که می‌تواند به عملکرد برنامه شما و سایر برنامه‌های دستگاه آسیب برساند. این روال‌های مطلوب را دنبال کنید تا مطمئن شوید برنامه‌تان بهترین عملکرد را دارد.

استفاده از کتابخانه‌های بار کردن تصویر

می‌توانید بااستفاده از کتابخانه‌های بار کردن تصویر، مثل Coil (برای پروژه‌های Kotlin-first) یا Glide (برای پروژه‌های Java)، کارایی برنامه‌تان را بهبود دهید. این کتابخانه‌ها با انجام کارهایی مثل ذخیره کردن تصاویر در حافظه نهان، نمونه‌کاهی گرافیک درصورت نیاز، و بازیافت اشیای گرافیکی، استفاده از حافظه برنامه‌تان را کاهش می‌دهند.

کاهش نرخ نمونه‌برداری تصاویر

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

کاهش نرخ نمونه‌برداری سمت کارخواه

کتابخانه‌های بار کردن تصویر مثل Coil و Glide نمونه‌کاهی را به‌طور خودکار برای شما انجام می‌دهند. می‌توانید راهبردهای نمونه‌کاهی آن‌ها را بااستفاده از ImageLoader (برای Coil) یا DownsampleStrategy (برای Glide) پیکربندی کنید. اگر بیت‌مپ‌ها را به‌صورت دستی مدیریت می‌کنید، می‌توانید از inSampleSize برای کدگشایی نسخه کوچک‌تر استفاده کنید. برای انجام ایمن این کار، باید ابتدا inJustDecodeBounds را روی true تنظیم کنید تا ابعاد تصویر را بدون اختصاص حافظه بخوانید، اندازه نمونه را محاسبه کنید، inSampleSize را روی آن مقدار تنظیم کنید، inJustDecodeBounds را روی false تنظیم کنید، و سپس تصویر را رمزگشایی کنید.

ترجیح دادن تغییر اندازه سمت سرور

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

می‌توانید کتابخانه‌ها را پیکربندی کنید تا اندازه نمای هدف را به‌طور پویا به نشانی وب تصویر اضافه کنند. برای مثال، Coil این کار را بااستفاده از رهگیرهای سفارشی امکان‌پذیر می‌کند و Glide بااستفاده از بارکننده‌های مدل سفارشی (مانند BaseGlideUrlLoader) از آن پشتیبانی می‌کند.

از اندازه‌های چیدمان نامحدود اجتناب کنید

برای اینکه بارکننده‌های تصویر به‌طور مؤثر نمونه‌کاهی کنند (سمت کارخواه یا سمت سرور)، باید اندازه هدف را قبل‌از اجرای درخواست بدانند.

از استفاده از wrapContentSize یا رها کردن ابعاد بدون محدودیت در ترکیب‌پذیرهایی که تصاویر راه دور را بار می‌کنند خودداری کنید. اگر این کتابخانه‌ها نتوانند مرزهای هدف را استنباط کنند، به بار کردن تصویر اصلی با اندازه کامل برمی‌گردند. این کار می‌تواند منجر به بار کردن تصویری بسیار بزرگ‌تر از حد لازم شود و استفاده از حافظه و تأخیر را افزایش دهد.

درعوض، ابعاد صریحی را برای تصویر ترکیب‌پذیرتان تنظیم کنید (برای مثال، بااستفاده از Modifier.size) یا نسبت ابعادی تعریف کنید. این کار به موتور چیدمان اجازه می‌دهد هدف دقیق پیکسل را ازقبل محاسبه کند، سپس بارکننده تصویر می‌تواند از آن برای درخواست و رمزگشایی دارایی با اندازه صحیح استفاده کند.

ارائه منابع جایگزین برای اندازه‌های مختلف صفحه‌نمایش

اگر با برنامه‌تان تصویر ارسال می‌کنید، دارایی‌هایی با اندازه‌های مختلف برای وضوح‌های مختلف دستگاه ارائه دهید. این کار می‌تواند به کاهش اندازه بارگیری برنامه شما در دستگاه‌ها کمک کند و عملکرد را بهبود بخشد، زیرا تصویری با وضوح پایین‌تر را در دستگاهی با وضوح پایین‌تر بار می‌کند. برای اطلاعات بیشتر درباره ارائه نگاشت‌های بیتی جایگزین برای اندازه‌های مختلف دستگاه، اسناد نگاشت بیتی جایگزین را بررسی کنید.

لایه‌گذاری را مستقیماً اعمال نکنید

گاهی ممکن است لازم باشد به تصویر حاشیه اضافه کنید. برای مثال، ممکن است بخواهید تصویر را با حاشیه شفافی برای عریض کردن احاطه کنید. در این شرایط، حاشیه را مستقیماً به تصویر اضافه نکنید، چون ابعاد تصویر تغییر می‌کند. درعوض، ابعاد تصویر را همان‌طور که هست رها کنید، و مکان تصویر را در صفحه بااستفاده از InsetDrawable تنظیم کنید. Alternatively, you can add padding into the Composable or View holding the image.

قالب پیکسل مناسب را انتخاب کنید

با انتخاب قالب پیکسل مناسب، بین حافظه و کیفیت تعادل برقرار کنید. وقتی به شفافیت نیاز ندارید، از RGB_565 استفاده کنید؛ این قالب نیمی از حافظه قالب پیش‌فرض ARGB_8888 را استفاده می‌کند.

در Glide می‌توانید این را بااستفاده از DecodeFormat پیکربندی کنید. در Coil، می‌توانید از ویژگی bitmapConfig استفاده کنید.

درصورت امکان از بردارها استفاده کنید

برای تصاویر متشکل از اشکال هندسی، گرافیک برداری بسیار کوچک‌تر از بیت‌مپ است و به‌راحتی برای هر تراکم نمایشی مقیاس‌بندی می‌شود. درصورت مناسب بودن، از عناصری مثل ShapeDrawable برای نمایش گرافیک استفاده کنید.

هرزمان که می‌توانید بیت‌مپ‌ها را منتشر کنید و دوباره از آن‌ها استفاده کنید

فایل‌های گرافیکی بزرگ می‌توانند حافظه زیادی را اشغال کنند. برای کاهش تأثیر آن‌ها، باید هرزمان که می‌توانید اشیای گرافیکی را آزاد کنید یا دوباره از آن‌ها استفاده کنید.

اگر از کتابخانه بارگیری تصویر استفاده می‌کنید، حتماً نقشه‌های بیتی را وقتی دیگر به آن‌ها نیاز ندارید به استخر مدیریت‌شده کتابخانه منتشر کنید. کتابخانه می‌تواند درصورت نیاز از اشیاء مجدداً استفاده کند و میان‌گیر حافظه را برای نیازهای آینده دردسترس نگه دارد.

اگر گرافیک را به‌صورت دستی مدیریت می‌کنید، باید بیت‌مپ‌ها را پس‌از اتمام کار با آن‌ها با فراخوانی Bitmap.recycle آزاد کنید و بلافاصله مرجع Bitmap را دور بیندازید، به‌جای اینکه به جمع‌آوری زباله تکیه کنید.

نکته‌ها و ترفندهای دیگر

این بخش چند روش دیگر را برای بهبود عملکرد برنامه شما هنگام مدیریت گرافیک فهرست می‌کند.

تصاویر بزرگ را با فایل AAB/APK خود بسته‌بندی نکنید

یکی از دلایل اصلی حجم بالای بارگیری برنامه، گرافیک‌هایی است که در فایل AAB یا APK بسته‌بندی شده‌اند. از ابزار تحلیل‌کننده APK استفاده کنید تا مطمئن شوید فایل‌های تصویری بزرگ‌تر از حد نیاز را بسته‌بندی نمی‌کنید. اندازه را کاهش دهید یا تصاویر را در سرور قرار دهید و فقط درصورت نیاز آن‌ها را بارگیری کنید.

پیدا کردن نگاشت‌های بیتی زائد

اگر چند نسخه از یک تصویر داشته باشید، حافظه هدر می‌رود. می‌توانید از تحلیل‌گر «استودیو Android» برای شناسایی گرافیک‌های زائد استفاده کنید. از تحلیل‌گر رونوشت پشته برای ضبط رونوشت پشته استفاده کنید و نتایج را با انتخاب تنظیم بیت‌مپ‌های تکراری فیلتر کنید.

هنگام استفاده از ImageBitmap، قبل‌از ترسیم، prepareToDraw را فراخوانی کنید

هنگام استفاده از ImageBitmap، برای شروع فرایند بارگذاری بافت در GPU، قبل‌از ترسیم واقعی آن، ImageBitmap#prepareToDraw() را فراخوانی کنید. این کار به واحد پردازش گرافیکی کمک می‌کند بافت را آماده کند و عملکرد نمایش تصویر را در صفحه‌نمایش بهبود بخشد. اکثر کتابخانه‌های بارگیری تصویر این بهینه‌سازی را انجام می‌دهند، اما اگر خودتان با کلاس ImageBitmap کار می‌کنید، باید این نکته را به‌خاطر داشته باشید.

ترجیحاً Int DrawableRes یا نشانی وب را به‌عنوان پارامتر به ترکیب‌پذیر خود ارسال کنید، نه Painter

به‌دلیل پیچیدگی‌های مربوط به تصاویر (برای مثال، نوشتن تابع برابری برای Bitmaps ازنظر محاسباتی پرهزینه خواهد بود)، Painter API صریحاً با حاشیه‌نویسی @Stable به‌عنوان پایدار علامت‌گذاری نشده است. کلاس‌های ناپایدار می‌توانند به بازترکیب‌های غیرضروری منجر شوند زیرا کامپایلر نمی‌تواند به‌راحتی تشخیص دهد که داده‌ها تغییر کرده‌اند یا نه.

بنابراین، توصیه می‌کنیم به‌جای ارسال Painter به‌عنوان پارامتر، یک نشانی وب یا شناسه منبع ترسیم‌شدنی را به‌عنوان پارامتر به composable خود ارسال کنید.

// Prefer this:
@Composable
fun MyImage(url: String) {

}
// Over this:
@Composable
fun MyImage(painter: Painter) {

}