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

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


در برنامه نویسی اندروید، کار شما با دستگاهی کوچک است که امکانات سخت افزاری محدودی نسبت به یک کامپیوتر خانگی یا یک لپتاپ دارد. Process های سنگینی مثل GUI، و Phone مقداری از حافظه‎ی RAM دستگاهتان را می‎گیرد و شما فضای کم‎تری برای استفاده در برنامه‎ی خود در اختیار دارید.

شاید گوشی‎های قوی امروز با 3 گیگابایت RAM و پردازنده‎ی 2.3 گیگاهرتز شامل این نگرانی نباشند اما باید در نظر گرفت که برنامه‎ی شما قرار است روی تمام دستگاه‎های اندرویدی (یا حداقل بیشترشان) بدون مشکل اجرا شود.

 

برنامه‎های موفق اندروید معمولا از انیمیشن‎های زیبا و گرافیک کاربرپسندی برخوردارهستند، و استفاده از عکس در جاهای مختلف یک اپلیکیشن خوب، دور از انتظار نیست. اما اگر از دید یک برنامه نویس به ظاهر و کارکرد یک اپلیکیشن موفق نگاه کنیم و یک برنامه‎ی Ram Usage Monitor داشته باشیم، می‎بینیم نهایت اسفاده‎ی آن برنامه از RAM ، به 50 مگابایت هم نمی‎رسد.

در برنامه نویسی اندروید، بعد از طراحی ظاهر برنامه مهم ترین مسئله، استفاده‎ی بهینه از منابع به خصوص حافظه‎ی RAM است. بدون توجه به این مسئله برنامه شما ممکن از کمتر از 5 دقیقه برای کاربر کار کند و مفید باشد، زیرا بعد از آن یا سرعت برنامه‎تان به شدت پایین می آید یا به علت کمبود بیش از حد RAM، اندروید برنامه شما را می‎بندد (Process آن را Kill می‎کند) بدون توجه به آن که شما در متد onDestroy یا onStop چه چیزهایی نوشته باشید.

چندین المان در برنامه نویسی هستند که از نظر مصرف حافظه‎ی RAM یکی از خط قرمزهای ما محسوب می‎شوند

  • متغیرها و کلاس‎هایی که خودمان طراحی کردیم

کلاس‎هایی که برای خواناتر کردن برنامه تان می‎نویسید احتمالا یکی از چیزهایی ست که باید بعد از اتمام کار، از نظر مصرف RAM بهینه شوند. اگر درون یک حلقه در هر گام، یک شیء از کلاستان می‎سازید بهتر است راه دیگری را برای اجرا کردن آن قطعه کد انتخاب کنید. درست است که Garbage Collector در اندروید بسیار خوب عمل می‎کند و شما لازم نیست نگران کلاس‎هایتان باشید، اما اگر در کلاستان از Bitmap استفاده می‎کنید، اعتماد کردن به GC کمی ریسک محسوب می‎شود.

سعی کنید متغیرهایی با طول زیاد به صورت ایستا (static) تعریف نکنید. منظور از متغیرهایی با طول زیاد، چیزهایی نظیر Bitmap است.

  • عکس

اگر در برنامه‎تان از عکس استفاده می‎کنید (که به احتمال خیلی زیاد استفاده می‎کنید) چه این عکس به صورت یک resource برای برنامه‎تان باشد و چه از اینترنت یا حافظه‎ی داخلی بارگذاری شود، یک خطر بسیار جدی برای برنامه‎تان محسوب می‎شود. عکس ها به طور بی‎رحمانه‎ای RAM مصرف می‎کنند و یکی از اصلی ترین علت خطای out of memory هستند.

سخت ترین کارتان زمانی است که عکس ها را از اینترنت دریافت می‎کنید و در یک لیست نشان می‎دهید، در این حالت نه حجم عکس مشخص است، نه تعداد آیتم‎هایی که کاربر از لیست می‎تواند ببیند (به علت اندازه‎های مختلف صفحه نمایش).

اندازه‎ی عکس‎ها باید قبل از نمایش داده شدن در برنامه‎تان، بسته به ابعاد ImageView (یا هر ابزاری که عکس را با آن نمایش می‎دهید) کمتر شوند. همچنین باید توجه داشت که در این کم شدن ابعاد، تغییر کیفیت محسوس نداشته باشید.

این روییه چند مرحله و چند پیش زمینه می‎خواهد که به طور خلاصه به آن ها اشاره می‎کنیم.

  1. کاربرد پوشه‎ی values در پوشه‎های پروژه‎ی خود را بشناسید و حالت‎های مختلف این پوشه را در اندازه‎های مختلف صفحه نمایش و موقعیت‎های مختلف پیاده سازی کنید. مثلا values-large برای تبلت‎های 7 و 8 اینچی و values-fa برای زمانی که زبان برنامه، فارسی است. در این پوشه فایلی به نام dimens.xml وجود دارد که بهتر است برای تعیین ابعاد ابزارهای مختلف از این فایل استفاده کنید
  2. صفحه‎ی مربوط به بارگذاری عکس‎های حجیم را در سایت توسعه دهندگان اندروید بخوانید.
  3. کاربرد متدهای کلاس BitmapFactory را بشناسید. متدهایی برای بارگذاری عکس از اینترنت یا حافظه داخلی گوشی در این کلاس وجود دارند که باعث می‎شوند سر و کار شما به این کلاس زیاد بیفتد.
  4. اگر عکسی جزء resource برنامه شما محسوب می‎شود و در پوشه ی drawable قرار دارد، سعی کنید در صورت امکان نسخه‎های مختلفی از نظر ابعاد برای پوشه‎های drawable-small، drawable-medium و… قرار دهید.

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

راه دیگری برای کاهش ابعاد عکس وجود دارد. برای این کار، در ابتدا باید ابعاد عکس را بگیرید، و با توجه به ابعاد ابزار نمایش دهنده‎ی عکس، متغیر inSampleSize را محاسبه کنید (متدی برای محاسبه در همان صفحه‎ی توسعه دهندگان وجود دارد) برای این کار حتما باید یک شیء از کلاس  BitmapFactory.Options بسازید و متغیر inJustDecodeBounds را true قرار دهید. سپس بعد از محاسبه‎ی inSampleSize با مقدار false برای متغیر inJustDecodeBounds اقدام به بارگذاری عکس کنید. مانند قطعه کد زیر :

BitmapFactory.Options opts =newBitmapFactory.Options(); opts.inJustDecodeBounds =true;BitmapFactory.decodeFile(“yourImagePath”, opts); opts.outHeight;//this is the image Height opts.outWidth;//this is the Image Widthint inSampleSize =CalculateInSampleSize(opts, myImageViewHeight, myImageViewWidth); opts.inSampleSize = inSampleSize; opts.inJustDecodeBounds =false;Bitmap scaledBitmap =BitmapFactory.decodeFile(“yourImagePath”, opts);//this is scaled down picture

 

این متغیر یک عدد مجذور 2 است که کلاس BitmapFactory از آن استفاده می‎کند تا ابعاد عکس شما را تقسیم بر این متغیر کند. به زبان دیگر، اگر inSampleSize عدد 2 باشد، هر 4 پیکسل از عکس، به 1 پیکسل نگاشت می‎شود.

با این روش شما می‎توانید مطمئن باشید که کیفیت عکس پایین نمی‎آید. اما محدودیتی که این روش دارد این است که متغیر inSampleSize حتما بایستی عددی مجذور 2 باشد، اگر شما عکسی با عرض 650 می‎خواهید، ممکن است متغیر inSampleSize با عدد 2 بتواند عرض را به 700 برساند و با عدد 4، عرض این عکس 350 می‎شود؛ که بیش از حد کوچک است.

پس بهترین راه برای آنکه عکس مورد نظر را دقیقا در ابعادی که می‎خواهید دریافت کنید این است که از متغیر inSampleSize و متد createScaledBitmap به طور همزمان استفاده کنید.

 

اما تمام این داستان برای بارگذاری عکس از اینترنت متفاوت است، زیرا قطعا این که یک بار عکس را دریافت کنیم تا فقط ابعاد آن را اندازه بگیریم و برای نمایش آن، یک بار دیگر مجبور باشیم عکس را از سرور بگیریم، اشتباه است.

برای این کار، من از کتابخانه‎های زیادی استفاده کردم و خودم هم اقدام به نوشتن یک کتابخانه برای دریافت عکس از اینترنت کردم. اما بهترین کتابخانه‎ای که با آن کار کردم و از امکاناتش استفاده کردم، Universal Image Loader بود. امکانات زیادی برای کش کردن، تغییر ابعاد عکس در این کتابخانه وجود دارد که به احتمال زیاد در برنامه‎تان مورد استفاده قرار می‎گیرند.

  •  لیست

لیست‎ها به دلیل اینکه چندین view را به طور همزمان نمایش می‎دهند می‎توانند یکی از خطرات مصرف RAM در برنامه شما باشند. ListView و GridView پر کاربرد ترین ابزارها در این دسته هستند. معمولا از یک customAdapter برای نمایش داده‎ها در لیست استفاده می‎شود، در پیاده سازی این Adapter چه از نوع BaseAdapter باشد، چه ArrayAdapter، در متد getView یک متغیر به نام convertView دارید. کار این متغیر، نگه داری آیتم‎هایی ست که اکنون از دید کاربر خارج شده‎اند و ممکن است نیازی به مقادیرشان نداشته باشید. بهتر است جهت ساختن view از این متغیر استفاده کنید و مقادیر آن را با توجه به آیتمی که کاربر آن را می‎بیند تغییر دهید. با این کار هم حافظه‎ی آن آیتم را آزاد می‎کنید، هم نیازی به inflate کردن یک view جدید ندارید.

منبع: blog.sariina.com


ارسال دیدگاه