بارگذاری نقشه های بیت بزرگ به طور موثر
با مجموعهها، منظم بمانید
ذخیره و طبقهبندی محتوا براساس اولویتهای شما.
توجه: چندین کتابخانه وجود دارد که بهترین شیوه ها را برای بارگذاری تصاویر دنبال می کنند. می توانید از این کتابخانه ها در برنامه خود برای بارگذاری تصاویر به بهینه ترین حالت استفاده کنید. ما کتابخانه Glide را توصیه می کنیم که تصاویر را تا حد امکان سریع و روان بارگیری و نمایش می دهد. دیگر کتابخانههای محبوب بارگیری تصویر عبارتند از Picasso from Square، Coil از Instacart و Fresco از Facebook. این کتابخانه ها بیشتر کارهای پیچیده مرتبط با بیت مپ و انواع دیگر تصاویر را در اندروید ساده می کنند.
تصاویر در همه اشکال و اندازه ها هستند. در بسیاری از موارد، آنها بزرگتر از حد مورد نیاز برای یک رابط کاربری نرم افزار معمولی (UI) هستند. به عنوان مثال، برنامه گالری سیستم عکسهای گرفته شده با استفاده از دوربین دستگاههای اندرویدی شما را نمایش میدهد که معمولاً وضوح بسیار بالاتری نسبت به تراکم صفحه نمایش دستگاه شما دارند.
با توجه به اینکه با حافظه محدود کار می کنید، در حالت ایده آل فقط می خواهید نسخه ای با وضوح پایین تر را در حافظه بارگذاری کنید. نسخه با وضوح پایین تر باید با اندازه مؤلفه UI که آن را نمایش می دهد مطابقت داشته باشد. تصویری با وضوح بالاتر هیچ مزیت قابل مشاهده ای را ارائه نمی دهد، اما همچنان حافظه گرانبهایی را اشغال می کند و به دلیل مقیاس گذاری بیشتر در حین انجام کار، هزینه بیشتری را متحمل می شود.
این درس شما را در رمزگشایی بیت مپ های بزرگ بدون تجاوز از محدودیت حافظه هر برنامه با بارگذاری یک نسخه کوچکتر زیر نمونه در حافظه راهنمایی می کند.
ابعاد و نوع بیت مپ را بخوانید
کلاس BitmapFactory
چندین روش رمزگشایی ( decodeByteArray()
، decodeFile()
، decodeResource()
و غیره) را برای ایجاد یک Bitmap
از منابع مختلف ارائه می دهد. مناسب ترین روش رمزگشایی را بر اساس منبع داده تصویر خود انتخاب کنید. این روش ها تلاش می کنند تا حافظه را برای بیت مپ ساخته شده تخصیص دهند و بنابراین به راحتی می توانند منجر به یک استثنا OutOfMemory
شوند. هر نوع روش رمزگشایی دارای امضاهای اضافی است که به شما امکان می دهد گزینه های رمزگشایی را از طریق کلاس BitmapFactory.Options
مشخص کنید. تنظیم ویژگی inJustDecodeBounds
روی true
در حین رمزگشایی، از تخصیص حافظه جلوگیری می کند، برای شی بیت مپ null
برمی گرداند اما outWidth
، outHeight
و outMimeType
تنظیم می کند. این تکنیک به شما امکان می دهد ابعاد و نوع داده های تصویر را قبل از ساخت (و تخصیص حافظه) بیت مپ بخوانید.
کاتلین
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeResource(resources, R.id.myimage, options)
val imageHeight: Int = options.outHeight
val imageWidth: Int = options.outWidth
val imageType: String = options.outMimeType
جاوا
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
برای جلوگیری از استثناهای java.lang.OutOfMemory
، قبل از رمزگشایی، ابعاد یک بیت مپ را بررسی کنید، مگر اینکه کاملاً به منبع اطمینان داشته باشید که داده های تصویر با اندازه قابل پیش بینی را در اختیار شما قرار می دهد که به راحتی در حافظه موجود قرار می گیرند.
یک نسخه کوچک شده را در حافظه بارگذاری کنید
اکنون که ابعاد تصویر مشخص شده است، می توان از آنها برای تصمیم گیری در مورد اینکه آیا تصویر کامل باید در حافظه بارگذاری شود یا به جای آن یک نسخه زیر نمونه بارگذاری شده استفاده کرد. در اینجا چند فاکتور برای در نظر گرفتن وجود دارد:
- استفاده تخمینی از حافظه برای بارگذاری تصویر کامل در حافظه.
- مقدار حافظه ای که می خواهید برای بارگیری این تصویر با توجه به سایر نیازهای حافظه برنامه خود متعهد شوید.
- ابعاد
ImageView
یا مؤلفه رابط کاربری هدف که تصویر باید در آن بارگذاری شود. - اندازه و چگالی صفحه نمایش دستگاه فعلی.
برای مثال، ارزش بارگذاری یک تصویر 1024x768 پیکسل در حافظه را ندارد، اگر در نهایت در یک تصویر کوچک پیکسلی 128x96 در ImageView
نمایش داده شود.
برای اینکه به رسیور بگویید که تصویر را نمونه برداری کند، با بارگذاری یک نسخه کوچکتر در حافظه، inSampleSize
در شی BitmapFactory.Options
خود روی true
تنظیم کنید. به عنوان مثال، یک تصویر با وضوح 2048x1536 که با inSampleSize
4 رمزگشایی شده است، یک بیت مپ تقریباً 512x384 تولید می کند. بارگیری این در حافظه از 0.75 مگابایت به جای 12 مگابایت برای تصویر کامل استفاده می کند (با فرض پیکربندی بیت مپ ARGB_8888
). در اینجا روشی برای محاسبه مقدار اندازه نمونه وجود دارد که توان دو بر اساس عرض و ارتفاع هدف است:
کاتلین
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
// Raw height and width of image
val (height: Int, width: Int) = options.run { outHeight to outWidth }
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
val halfHeight: Int = height / 2
val halfWidth: Int = 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 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;
}
توجه: توان دو مقدار محاسبه می شود زیرا رمزگشا از یک مقدار نهایی با گرد کردن به نزدیکترین توان دو، مطابق مستندات inSampleSize
، استفاده می کند.
برای استفاده از این روش، ابتدا با inJustDecodeBounds
که روی true
تنظیم شده است رمزگشایی کنید، گزینه ها را عبور دهید و سپس با استفاده از مقدار جدید inSampleSize
و inJustDecodeBounds
روی false
دوباره رمزگشایی کنید:
کاتلین
fun decodeSampledBitmapFromResource(
res: Resources,
resId: Int,
reqWidth: Int,
reqHeight: Int
): Bitmap {
// First decode with inJustDecodeBounds=true to check dimensions
return BitmapFactory.Options().run {
inJustDecodeBounds = true
BitmapFactory.decodeResource(res, resId, this)
// Calculate inSampleSize
inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)
// Decode bitmap with inSampleSize set
inJustDecodeBounds = false
BitmapFactory.decodeResource(res, resId, this)
}
}
جاوا
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);
}
این روش بارگذاری یک بیت مپ با اندازه دلخواه بزرگ را در ImageView
که یک تصویر کوچک 100x100 پیکسل را نمایش می دهد، آسان می کند، همانطور که در کد مثال زیر نشان داده شده است:
کاتلین
imageView.setImageBitmap(
decodeSampledBitmapFromResource(resources, R.id.myimage, 100, 100)
)
جاوا
imageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
میتوانید با جایگزین کردن روش BitmapFactory.decode*
مناسب، فرآیند مشابهی را برای رمزگشایی بیتمپها از منابع دیگر دنبال کنید.
محتوا و نمونه کدها در این صفحه مشمول پروانههای توصیفشده در پروانه محتوا هستند. جاوا و OpenJDK علامتهای تجاری یا علامتهای تجاری ثبتشده Oracle و/یا وابستههای آن هستند.
تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی.
[null,null,["تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی."],[],[],null,["# Loading Large Bitmaps Efficiently\n\n**Note:** There are several libraries that follow\nbest practices for loading images. You can use these libraries in your app to\nload images in the most optimized manner. We recommend the\n[Glide](https://github.com/bumptech/glide)\nlibrary, which loads and displays images as quickly and smoothly as possible.\nOther popular image loading libraries include [Picasso](http://square.github.io/picasso/) from Square, [Coil](https://github.com/coil-kt/coil) from Instacart, and\n[Fresco](https://github.com/facebook/fresco)\nfrom Facebook. These libraries simplify most of the complex tasks associated\nwith bitmaps and other types of images on Android.\n\nImages come in all shapes and sizes. In many cases they are larger than required for a typical\napplication user interface (UI). For example, the system Gallery application displays photos taken\nusing your Android devices's camera which are typically much higher resolution than the screen\ndensity of your device.\n\nGiven that you are working with limited memory, ideally you only want to load a lower resolution\nversion in memory. The lower resolution version should match the size of the UI component that\ndisplays it. An image with a higher resolution does not provide any visible benefit, but still takes\nup precious memory and incurs additional performance overhead due to additional on the fly\nscaling.\n\nThis lesson walks you through decoding large bitmaps without exceeding the per application\nmemory limit by loading a smaller subsampled version in memory.\n\nRead Bitmap Dimensions and Type\n-------------------------------\n\nThe [BitmapFactory](/reference/android/graphics/BitmapFactory) class provides several decoding methods ([decodeByteArray()](/reference/android/graphics/BitmapFactory#decodeByteArray(byte[], int, int, android.graphics.BitmapFactory.Options)), [decodeFile()](/reference/android/graphics/BitmapFactory#decodeFile(java.lang.String, android.graphics.BitmapFactory.Options)), [decodeResource()](/reference/android/graphics/BitmapFactory#decodeResource(android.content.res.Resources, int, android.graphics.BitmapFactory.Options)), etc.) for creating a [Bitmap](/reference/android/graphics/Bitmap) from various sources. Choose\nthe most appropriate decode method based on your image data source. These methods attempt to\nallocate memory for the constructed bitmap and therefore can easily result in an `OutOfMemory`\nexception. Each type of decode method has additional signatures that let you specify decoding\noptions via the [BitmapFactory.Options](/reference/android/graphics/BitmapFactory.Options) class. Setting the [inJustDecodeBounds](/reference/android/graphics/BitmapFactory.Options#inJustDecodeBounds) property to `true` while decoding\navoids memory allocation, returning `null` for the bitmap object but setting [outWidth](/reference/android/graphics/BitmapFactory.Options#outWidth), [outHeight](/reference/android/graphics/BitmapFactory.Options#outHeight) and [outMimeType](/reference/android/graphics/BitmapFactory.Options#outMimeType). This technique allows you to read the\ndimensions and type of the image data prior to construction (and memory allocation) of the\nbitmap. \n\n### Kotlin\n\n```kotlin\nval options = BitmapFactory.Options().apply {\n inJustDecodeBounds = true\n}\nBitmapFactory.decodeResource(resources, R.id.myimage, options)\nval imageHeight: Int = options.outHeight\nval imageWidth: Int = options.outWidth\nval imageType: String = options.outMimeType\n```\n\n### Java\n\n```java\nBitmapFactory.Options options = new BitmapFactory.Options();\noptions.inJustDecodeBounds = true;\nBitmapFactory.decodeResource(getResources(), R.id.myimage, options);\nint imageHeight = options.outHeight;\nint imageWidth = options.outWidth;\nString imageType = options.outMimeType;\n```\n\nTo avoid `java.lang.OutOfMemory` exceptions, check the dimensions of a bitmap before\ndecoding it, unless you absolutely trust the source to provide you with predictably sized image data\nthat comfortably fits within the available memory.\n\nLoad a Scaled Down Version into Memory\n--------------------------------------\n\nNow that the image dimensions are known, they can be used to decide if the full image should be\nloaded into memory or if a subsampled version should be loaded instead. Here are some factors to\nconsider:\n\n- Estimated memory usage of loading the full image in memory.\n- Amount of memory you are willing to commit to loading this image given any other memory requirements of your application.\n- Dimensions of the target [ImageView](/reference/android/widget/ImageView) or UI component that the image is to be loaded into.\n- Screen size and density of the current device.\n\nFor example, it's not worth loading a 1024x768 pixel image into memory if it will eventually be\ndisplayed in a 128x96 pixel thumbnail in an [ImageView](/reference/android/widget/ImageView).\n\nTo tell the decoder to subsample the image, loading a smaller version into memory, set [inSampleSize](/reference/android/graphics/BitmapFactory.Options#inSampleSize) to `true` in your [BitmapFactory.Options](/reference/android/graphics/BitmapFactory.Options) object. For example, an image with resolution 2048x1536 that\nis decoded with an [inSampleSize](/reference/android/graphics/BitmapFactory.Options#inSampleSize) of 4 produces a\nbitmap of approximately 512x384. Loading this into memory uses 0.75MB rather than 12MB for the full\nimage (assuming a bitmap configuration of [ARGB_8888](/reference/android/graphics/Bitmap.Config)). Here's\na method to calculate a sample size value that is a power of two based on a target width and\nheight: \n\n### Kotlin\n\n```kotlin\nfun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {\n // Raw height and width of image\n val (height: Int, width: Int) = options.run { outHeight to outWidth }\n var inSampleSize = 1\n\n if (height \u003e reqHeight || width \u003e reqWidth) {\n\n val halfHeight: Int = height / 2\n val halfWidth: Int = width / 2\n\n // Calculate the largest inSampleSize value that is a power of 2 and keeps both\n // height and width larger than the requested height and width.\n while (halfHeight / inSampleSize \u003e= reqHeight && halfWidth / inSampleSize \u003e= reqWidth) {\n inSampleSize *= 2\n }\n }\n\n return inSampleSize\n}\n```\n\n### Java\n\n```java\npublic static int calculateInSampleSize(\n BitmapFactory.Options options, int reqWidth, int reqHeight) {\n // Raw height and width of image\n final int height = options.outHeight;\n final int width = options.outWidth;\n int inSampleSize = 1;\n\n if (height \u003e reqHeight || width \u003e reqWidth) {\n\n final int halfHeight = height / 2;\n final int halfWidth = width / 2;\n\n // Calculate the largest inSampleSize value that is a power of 2 and keeps both\n // height and width larger than the requested height and width.\n while ((halfHeight / inSampleSize) \u003e= reqHeight\n && (halfWidth / inSampleSize) \u003e= reqWidth) {\n inSampleSize *= 2;\n }\n }\n\n return inSampleSize;\n}\n```\n\n**Note:** A power of two value is calculated because the decoder uses\na final value by rounding down to the nearest power of two, as per the [inSampleSize](/reference/android/graphics/BitmapFactory.Options#inSampleSize) documentation.\n\nTo use this method, first decode with [inJustDecodeBounds](/reference/android/graphics/BitmapFactory.Options#inJustDecodeBounds) set to `true`, pass the options\nthrough and then decode again using the new [inSampleSize](/reference/android/graphics/BitmapFactory.Options#inSampleSize) value and [inJustDecodeBounds](/reference/android/graphics/BitmapFactory.Options#inJustDecodeBounds) set to `false`: \n\n### Kotlin\n\n```kotlin\nfun decodeSampledBitmapFromResource(\n res: Resources,\n resId: Int,\n reqWidth: Int,\n reqHeight: Int\n): Bitmap {\n // First decode with inJustDecodeBounds=true to check dimensions\n return BitmapFactory.Options().run {\n inJustDecodeBounds = true\n BitmapFactory.decodeResource(res, resId, this)\n\n // Calculate inSampleSize\n inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)\n\n // Decode bitmap with inSampleSize set\n inJustDecodeBounds = false\n\n BitmapFactory.decodeResource(res, resId, this)\n }\n}\n```\n\n### Java\n\n```java\npublic static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,\n int reqWidth, int reqHeight) {\n\n // First decode with inJustDecodeBounds=true to check dimensions\n final BitmapFactory.Options options = new BitmapFactory.Options();\n options.inJustDecodeBounds = true;\n BitmapFactory.decodeResource(res, resId, options);\n\n // Calculate inSampleSize\n options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);\n\n // Decode bitmap with inSampleSize set\n options.inJustDecodeBounds = false;\n return BitmapFactory.decodeResource(res, resId, options);\n}\n```\n\nThis method makes it easy to load a bitmap of arbitrarily large size into an [ImageView](/reference/android/widget/ImageView) that displays a 100x100 pixel thumbnail, as shown in the following example\ncode: \n\n### Kotlin\n\n```kotlin\nimageView.setImageBitmap(\n decodeSampledBitmapFromResource(resources, R.id.myimage, 100, 100)\n)\n```\n\n### Java\n\n```java\nimageView.setImageBitmap(\n decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));\n```\n\nYou can follow a similar process to decode bitmaps from other sources, by substituting the\nappropriate [BitmapFactory.decode*](/reference/android/graphics/BitmapFactory#decodeByteArray(byte[], int, int, android.graphics.BitmapFactory.Options)) method as needed."]]