Bitmap——BitmapFactory.Options

本文介绍如何使用BitmapFactory.Options减少图片加载时的内存占用,并提供了一种根据屏幕尺寸调整图片大小的方法。

转自http://blog.youkuaiyun.com/ruiyiin/article/details/8675361

加载和显示图片是很消耗内存的一件事,BitmapFactory.Options 类,  允许我们定义图片以何种方式如何读到内存,

BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();  
bmpFactoryOptions.inSampleSize = 8;  
Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);  
imv.setImageBitmap(bmp);

上面的代码使图片变成原来的1/8.

    //imv = (ImageView) findViewById(R.id.ReturnedImageView);  
            Display currentDisplay = getWindowManager().getDefaultDisplay();  
            int dw = currentDisplay.getWidth();  
            int dh = currentDisplay.getHeight();  
              try  
           {  
            BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();  
            bmpFactoryOptions.inJustDecodeBounds = true;  
            Bitmap bmp = BitmapFactory.decodeStream(getContentResolver().  
                    openInputStream(imageFileUri), null,  bmpFactoryOptions);  
      
            int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)dh);  
            int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)dw);  
      
            Log.v("HEIGHRATIO", ""+heightRatio);  
            Log.v("WIDTHRATIO", ""+widthRatio);  
      
            if (heightRatio > 1 && widthRatio > 1)  
            {  
                bmpFactoryOptions.inSampleSize =  heightRatio > widthRatio ? heightRatio:widthRatio;  
            }  
            bmpFactoryOptions.inJustDecodeBounds = false;  
            bmp = BitmapFactory.decodeStream(getContentResolver().  
                    openInputStream(imageFileUri), null,  bmpFactoryOptions);  
               returnedImageView.setImageBitmap(bmp);  
           }  
           catch (FileNotFoundException e)  
           {  
               Log.v("ERROR", e.toString());  
      
           }  

上面的代码让图片根据窗口大小改变

bmpFactoryOptions.inJustDecodeBounds = true; 
这一行让代码只解码图片的Bounds

你现在的代码是: ```java Glide.with(context) .load(resourceName) .transform(new CircleCrop()) .error(circularBitmap) // 传入一个已经裁剪好的圆形 Bitmap .into(view); ``` 你想实现的效果是:**当网络图片加载失败时,显示一个圆形的默认图(error 图)**。 但你发现: ❌ `error(circularBitmap)` 虽然是圆形 Bitmap,但在某些情况下 **仍然显示为矩形或被拉伸**? --- ## ✅ 问题分析 虽然你传的是一个**已经裁剪成圆形的 `Bitmap`**,但 `.error()` 接收的是 `Drawable` 或 `Resource ID`,而 Glide 并不会对 `error` 图自动应用 `.transform()` 的变换! > 🔴 **关键点:`.transform(new CircleCrop())` 不会影响 `.error()` 设置的 Drawable!** 也就是说: - 成功加载的图片 → 使用 `CircleCrop()` 变成圆形 ✅ - 失败时显示的 `circularBitmap` → 直接作为 `BitmapDrawable` 显示,**不走 transform 流程** ❌ 所以即使你传了一个“视觉上”是圆的 Bitmap,如果 `ImageView` 是矩形,它仍可能被拉伸、边缘露出,看起来不像圆。 --- ## ✅ 正确解决方案:让 error 图也经过相同的圆形变换 ### ✅ 方法 1:使用 `RequestOptions` 统一 transform(推荐) 将 transform 提取到 `RequestOptions` 中,并用 `apply()` 同时作用于正常和错误状态。 ```java RequestOptions options = new RequestOptions() .transform(new CircleCrop()) // 所有情况都应用圆形裁剪 .placeholder(R.drawable.ic_placeholder) // 可选:加载中占位图 .error(R.drawable.default_avatar); // 注意:这里用资源 ID,不是 Bitmap Glide.with(context) .load(resourceName) .apply(options) .into(view); ``` ✅ 这样 `.error()` 的图片也会被 `CircleCrop()` 处理 → 自动变圆! > ⚠️ 建议把 `default_avatar.png` 放在 `res/drawable/` 下,Glide 会自动裁剪它。 --- ### ✅ 方法 2:如果你坚持要用 `Bitmap` 作为 error 图,必须包装成 `BitmapDrawable` 并确保 ImageView 裁剪 ```java // 先创建圆形 Bitmap Bitmap squareBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.img_home_sing); Bitmap circularBitmap = ImageUtils.getCircularBitmap(squareBitmap); // 包装成 Drawable BitmapDrawable errorDrawable = new BitmapDrawable(context.getResources(), circularBitmap); // 设置 scale type 防止拉伸 view.setScaleType(ImageView.ScaleType.CENTER_CROP); Glide.with(context) .load(resourceName) .transform(new CircleCrop()) .error(errorDrawable) .into(view); ``` 同时确保你的 `ImageView` 在布局中设置了合适的 `ScaleType`: ```xml <ImageView android:id="@+id/iv_song_logo" android:layout_width="60dp" android:layout_height="60dp" android:scaleType="centerCrop" /> ``` --- ### ✅ 方法 3:最稳妥做法 —— 把默认图做成圆形 PNG 资源 👉 直接设计一张 **圆形的 PNG 图标**(如 `ic_default_avatar_circle.png`),然后: ```java Glide.with(context) .load(resourceName) .transform(new CircleCrop()) .error(R.drawable.ic_default_avatar_circle) .into(view); ``` 这样无论是否裁剪,视觉上都是圆的,避免任何渲染差异。 --- ## 🛠️ 补充建议:优化内存与性能 - ❌ 不要频繁调用 `BitmapFactory.decodeResource()`,尤其是在 `RecyclerView` 里。 - ✅ 将 `R.mipmap.img_home_sing` 缓存为静态资源或使用 `ResourcesCompat.getDrawable()` - ✅ 使用矢量图或固定尺寸 PNG 替代运行时解码 --- ## ✅ 最终推荐代码(简洁 + 安全 + 圆形一致) ```java ImageView view = baseViewHolder.getView(R.id.iv_song_logo); String resourceName = dataBean.getCover(); Log.d("ImageLoader", "Loading: " + resourceName); RequestOptions options = new RequestOptions() .transform(new CircleCrop()) .placeholder(R.drawable.ic_placeholder) .error(R.drawable.ic_default_avatar_circle); // 确保这个图是圆形设计 Glide.with(context) .load(resourceName) .apply(options) .into(view); ``` 布局文件中: ```xml <ImageView android:id="@+id/iv_song_logo" android:layout_width="60dp" android:layout_height="60dp" android:scaleType="centerCrop" /> ``` --- ## ✅ 效果对比 | 方案 | 是否保证 error 图是圆? | 是否高效 | 推荐度 | |------|--------------------------|----------|--------| | `.error(circularBitmap)` | ❌ 可能变形 | ❌ 每次 decode | ⭐☆☆ | | `.error(resId)` + `transform` | ✅ 自动裁剪 | ✅ 高效缓存 | ⭐⭐⭐⭐⭐ | | 使用圆形 PNG 作为 error 图 | ✅ 视觉上就是圆 | ✅ 最简单 | ⭐⭐⭐⭐ | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值