poorman
شنبه 19 بهمن 1392, 19:12 عصر
سلام دوستان
من بالاخره مشکلم رو حل کردم ، به همین مناسبت گفتم زکات علمم رو بدم و واسه کسایی که احیانا در آینده دچار مشکل من میشن ، توضیح بدم تا نخوان مثل من 2 روز کامل کل اینترنت رو بگردن
ابتدا بذارین یه توضیح بدم که خطای OOM یا همون Out Of Memory به چه دلیل رخ میده
سیستم عامل اندروید برای اجرای هر برنامه ، مقدار محدودی از حافظه رم رو در اختیار اون برنامه میذاره که متناسب با نوع دستگاه ، بین 16 تا 128 مگابایت هست
این حافظه کم ، وقتی که عکس های با اندازه بالا رو توی خودش لود میکنه ، به سرعت پر میشه ، به همین دلیل برنامه force close میده و اگر توی log سیستم ببینید ، هنگام کار با عکس ها یا setContentView می تونید خطای OOM رو ببینید
البته میدونید که force close دلایل متعددی داره ، و این تنها یکی از دلایلش هست
خب من برای رفع مشکلم چکار کردم ؟؟؟ اومدم چند تا حرکت زدم
حرکت اول اینکه توی هیچ فایل xml عکسی رو لود نکردم از resource
حرکت دوم ، توی متد onCreate هر اکتیویتی اومدم عکس ها رو لود کردم و قرار دادم
خب تا اینجای کار شما بازم ارور میگیرید ، پس عملا کاری نکردین ، بنابراین قسمتی که مهمه کوچیک کردن عکس های بزرگ هست
پس حرکت سوم اینه که شما با استفاده از دو تا تابع که سایت اندروید داده واسه کار کردن با bitmap های بزرگ ، عکس هاتون رو در اندازه مناسب کوچیک کنید
حالا چند تا ابهام هست ، اینکه گوشی های مختلف سایز های مختلف دارن ، و شما نمیدونید اندازه مناسب برای کوچیک کردن عکس چیه
من چون توی برنامه با عرض و طول صفحه زیاد کار دارم ، یک راه حل ساده دارم
توی اکتیویتی splash screen هنگام خروج میام عرض و طول layout رو توی یک کلاس عمومی ذخیره میکنم
حالا روی اینا مانور نمیدم چون طولانی میشه ...
خب اگر تعداد اکتیویتی هاتون زیاد هست ، این دو تا تابع رو توی یک کلاس جدا به اسم Module بنویسین که استفاده از اونها راحت تر باشه
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
خب حالا با استفاده از تابع decodeSampledBitmapFromResource می تونید عکس ها رو کوچیک کنید
یک مثال میزنم برای ست کردن بک گراند یک layout
Bitmap b = module.decodeSampledBitmapFromResource(getResource s(), R.drawable.reading_page, 480, 800);
readingPage = (LinearLayout) findViewById(R.id.readingPage);
readingPage.setBackgroundDrawable((BitmapDrawable) new BitmapDrawable(b));
خب الان عکستون به اندازه 480*800 کوچیک شد و ست شد
اگر باز هم ارور گرفتید توی این قسمت ، باید کیفیت عکس رو پایینتر بیارید
برای این کار توی تابع calculateInSampleSize که بالا نوشتم ، مقدار اولیه inSampleSize رو یکی اضافه کنید ، اگر باز هم ارور گرفتید مقدار رو به 3 تغییر بدید تا کیفیت به حداقل برسه ( من با مقدار 1 ارور میگرفتم )
خب تا اینجا شما عکس رو کوچیک کردید و ست کردین
برای احتیاط و اینکه هر وقت حافظه رو لازم نداشتین بتونین آزاد کنین ، انجام چند تا کار ضروری هست
اول اینکه متغیرهای Bitmap رو عمومی تعریف کنید
دوم در متد onStop هر اکتیویتی ، عکس تمام اشیاء و layout رو null کنید
فقط حواستون باشه که توی متد onRestart باید دوباره عکس اشیاء و layout رو مقدار بدین
سوم ، توی متد onStop تمام متغییر های Bitmap رو recycle کنید
b.Recycle();
کار تمومه ، دیگه خطای out of memory نخواهید گرفت
حالا موضوع دیگه اینکه ، شاید شما نخواین همیشه کیفیت و اندازه عکس رو بیارین پایین
راه حل خیلی ساده اینه که اول از راه معمولی عکس بک گراند یا هرچیزی رو ست کنید ، بعد اگر خطای OOM گرفتید با استفاده از try catch حالا مجبور هستید که کیفیت عکس رو بیارید پایین
بالاخره بهتر از کرش کردن برنامه هست
اینم یک نمونه کد برای این قسمت آخر
try {
readingPage.setBackgroundResource(R.drawable.readi ng_page);
} catch (OutOfMemoryError e) {
Bitmap b = module.decodeSampledBitmapFromResource(getResource s(), R.drawable.reading_page, 480, 800);
readingPage.setBackgroundDrawable((BitmapDrawable) new BitmapDrawable(b));
}
دهنم کف کرد دیگه ، آموزش نوشتن هم انصافا سخته :لبخند:
موفق باشید
من بالاخره مشکلم رو حل کردم ، به همین مناسبت گفتم زکات علمم رو بدم و واسه کسایی که احیانا در آینده دچار مشکل من میشن ، توضیح بدم تا نخوان مثل من 2 روز کامل کل اینترنت رو بگردن
ابتدا بذارین یه توضیح بدم که خطای OOM یا همون Out Of Memory به چه دلیل رخ میده
سیستم عامل اندروید برای اجرای هر برنامه ، مقدار محدودی از حافظه رم رو در اختیار اون برنامه میذاره که متناسب با نوع دستگاه ، بین 16 تا 128 مگابایت هست
این حافظه کم ، وقتی که عکس های با اندازه بالا رو توی خودش لود میکنه ، به سرعت پر میشه ، به همین دلیل برنامه force close میده و اگر توی log سیستم ببینید ، هنگام کار با عکس ها یا setContentView می تونید خطای OOM رو ببینید
البته میدونید که force close دلایل متعددی داره ، و این تنها یکی از دلایلش هست
خب من برای رفع مشکلم چکار کردم ؟؟؟ اومدم چند تا حرکت زدم
حرکت اول اینکه توی هیچ فایل xml عکسی رو لود نکردم از resource
حرکت دوم ، توی متد onCreate هر اکتیویتی اومدم عکس ها رو لود کردم و قرار دادم
خب تا اینجای کار شما بازم ارور میگیرید ، پس عملا کاری نکردین ، بنابراین قسمتی که مهمه کوچیک کردن عکس های بزرگ هست
پس حرکت سوم اینه که شما با استفاده از دو تا تابع که سایت اندروید داده واسه کار کردن با bitmap های بزرگ ، عکس هاتون رو در اندازه مناسب کوچیک کنید
حالا چند تا ابهام هست ، اینکه گوشی های مختلف سایز های مختلف دارن ، و شما نمیدونید اندازه مناسب برای کوچیک کردن عکس چیه
من چون توی برنامه با عرض و طول صفحه زیاد کار دارم ، یک راه حل ساده دارم
توی اکتیویتی splash screen هنگام خروج میام عرض و طول layout رو توی یک کلاس عمومی ذخیره میکنم
حالا روی اینا مانور نمیدم چون طولانی میشه ...
خب اگر تعداد اکتیویتی هاتون زیاد هست ، این دو تا تابع رو توی یک کلاس جدا به اسم Module بنویسین که استفاده از اونها راحت تر باشه
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
خب حالا با استفاده از تابع decodeSampledBitmapFromResource می تونید عکس ها رو کوچیک کنید
یک مثال میزنم برای ست کردن بک گراند یک layout
Bitmap b = module.decodeSampledBitmapFromResource(getResource s(), R.drawable.reading_page, 480, 800);
readingPage = (LinearLayout) findViewById(R.id.readingPage);
readingPage.setBackgroundDrawable((BitmapDrawable) new BitmapDrawable(b));
خب الان عکستون به اندازه 480*800 کوچیک شد و ست شد
اگر باز هم ارور گرفتید توی این قسمت ، باید کیفیت عکس رو پایینتر بیارید
برای این کار توی تابع calculateInSampleSize که بالا نوشتم ، مقدار اولیه inSampleSize رو یکی اضافه کنید ، اگر باز هم ارور گرفتید مقدار رو به 3 تغییر بدید تا کیفیت به حداقل برسه ( من با مقدار 1 ارور میگرفتم )
خب تا اینجا شما عکس رو کوچیک کردید و ست کردین
برای احتیاط و اینکه هر وقت حافظه رو لازم نداشتین بتونین آزاد کنین ، انجام چند تا کار ضروری هست
اول اینکه متغیرهای Bitmap رو عمومی تعریف کنید
دوم در متد onStop هر اکتیویتی ، عکس تمام اشیاء و layout رو null کنید
فقط حواستون باشه که توی متد onRestart باید دوباره عکس اشیاء و layout رو مقدار بدین
سوم ، توی متد onStop تمام متغییر های Bitmap رو recycle کنید
b.Recycle();
کار تمومه ، دیگه خطای out of memory نخواهید گرفت
حالا موضوع دیگه اینکه ، شاید شما نخواین همیشه کیفیت و اندازه عکس رو بیارین پایین
راه حل خیلی ساده اینه که اول از راه معمولی عکس بک گراند یا هرچیزی رو ست کنید ، بعد اگر خطای OOM گرفتید با استفاده از try catch حالا مجبور هستید که کیفیت عکس رو بیارید پایین
بالاخره بهتر از کرش کردن برنامه هست
اینم یک نمونه کد برای این قسمت آخر
try {
readingPage.setBackgroundResource(R.drawable.readi ng_page);
} catch (OutOfMemoryError e) {
Bitmap b = module.decodeSampledBitmapFromResource(getResource s(), R.drawable.reading_page, 480, 800);
readingPage.setBackgroundDrawable((BitmapDrawable) new BitmapDrawable(b));
}
دهنم کف کرد دیگه ، آموزش نوشتن هم انصافا سخته :لبخند:
موفق باشید