Android图片展示App添加图片卡顿及OOM问题求助
解决图片展示App的内存溢出与加载缓慢问题
嘿,你的问题根源其实是**对图片的处理方式太“笨重”**了——直接加载原图、转Base64存SharedPreferences,这两个操作几乎是OOM和卡顿的元凶。咱们一步步来优化:
核心问题分析
- 内存爆炸的元凶:直接解码原图为Bitmap,再转成Base64存储。一张1080P的PNG图可能占几十MB内存,多张叠加直接触发OOM;而且Base64会让数据体积膨胀33%,SharedPreferences根本不适合存大量二进制数据。
- 加载缓慢的原因:每次添加图片都调用
notifyDataSetChanged()刷新整个RecyclerView;Adapter中每次绑定都重复解码Base64为Bitmap,没有任何缓存机制。
具体优化方案
1. 放弃Base64,改用存储图片Uri
我们不需要把图片转成Base64存起来,直接保存图片的Uri字符串就够了——Uri本身只是个地址,体积极小,加载时再通过Uri去获取图片。
首先修改你的ImageModelClass,把image字段改为存储Uri字符串:
public class ImageModelClass { private String imageUri; // 替换原来的Base64字段 public String getImageUri() { return imageUri; } public void setImageUri(String imageUri) { this.imageUri = imageUri; } }
2. 修改Activity的图片选择与存储逻辑
在onActivityResult中,不再解码Bitmap,直接保存Uri的字符串:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) { assert data != null; if (data.getClipData() != null) { ClipData clipData = data.getClipData(); for (int i = 0; i < clipData.getItemCount(); i++) { Uri imageUri = clipData.getItemAt(i).getUri(); ImageModelClass model = new ImageModelClass(); model.setImageUri(imageUri.toString()); imageList.add(model); // 只刷新新增的item,比notifyDataSetChanged高效N倍 adapter.notifyItemInserted(imageList.size() - 1); } } else { Uri imageUri = data.getData(); if (imageUri != null) { ImageModelClass model = new ImageModelClass(); model.setImageUri(imageUri.toString()); imageList.add(model); adapter.notifyItemInserted(imageList.size() - 1); } } saveGalleryData(); } }
同时更新存储和加载方法(逻辑不变,但存储的是Uri列表,体积更小):
private void saveGalleryData() { SharedPreferences preferences = getSharedPreferences(IMAGE_SHARED_PREFS, MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); Gson gson = new Gson(); String json = gson.toJson(imageList); editor.putString(IMAGE_DATA_KEY, json); editor.apply(); } private void loadAlbumData() { SharedPreferences preferences = getSharedPreferences(IMAGE_SHARED_PREFS, MODE_PRIVATE); Gson gson = new Gson(); Type type = new TypeToken<ArrayList<ImageModelClass>>() {}.getType(); String data = preferences.getString(IMAGE_DATA_KEY, null); imageList = gson.fromJson(data, type); if (imageList == null) { imageList = new ArrayList<>(); } }
3. 用Glide处理图片加载(彻底解决OOM)
Glide是Android上最常用的图片加载库,它会自动:
- 根据ImageView的尺寸采样压缩图片,只加载需要的分辨率
- 管理内存和磁盘缓存,避免重复加载
- 自动回收Bitmap,防止内存泄漏
首先在build.gradle中添加Glide依赖(记得同步项目):
dependencies { implementation 'com.github.bumptech.glide:glide:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' }
然后修改Adapter,用Glide加载图片,去掉手动解码Base64的逻辑:
public class ImageCollectionAdapter extends RecyclerView.Adapter<ImageCollectionAdapter.MyViewHolder> { private List<ImageModelClass> list; private Context context; // 添加Context用于Glide初始化 public ImageCollectionAdapter(List<ImageModelClass> list, Context context) { this.list = list; this.context = context; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new MyViewHolder(LayoutInflater.from(parent.getContext()) .inflate(R.layout.image_collection_lists, parent, false)); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { ImageModelClass currentImage = list.get(position); Uri imageUri = Uri.parse(currentImage.getImageUri()); // 用Glide加载图片,自动处理压缩和缓存 Glide.with(context) .load(imageUri) .centerCrop() // 可选,根据你的布局需求调整为fitCenter等 .into(holder.imageView); } @Override public int getItemCount() { return list.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { RoundedImageView imageView; public MyViewHolder(@NonNull View itemView) { super(itemView); imageView = itemView.findViewById(R.id.galleryPicture); } } }
最后在Activity中初始化Adapter时传入Context:
adapter = new ImageCollectionAdapter(imageList, this);
4. 额外优化:清理无用代码
删除Activity中不再需要的encodeTobase64方法,以及Adapter中相关的Base64解码逻辑——这些现在都是多余的了。
优化后的效果
- 内存占用大幅降低:Glide只会加载ImageView尺寸对应的小Bitmap,不会一次性加载多张原图
- 添加图片速度明显提升:不再需要解码和转Base64,只存Uri字符串
- 滚动更流畅:RecyclerView只刷新新增item,Glide的缓存避免重复加载
内容的提问来源于stack exchange,提问作者Kaunain
相关产品推荐
相关产品推荐

