每天记录学习的新知识 : Android ImageView 使用和回收的方式

ImageView资源的利用和优化

1.利用Android Studio Profiler 工具解析应用的内存数据

因为想查看为ImageView设置图片时,内存的占用情况,故需要使用Profiler 工具。

在这里插入图片描述
当前项目,点击后运行即可。

在这里插入图片描述

内存类型包含:

  1. Java:
    从Java或Kotlin代码中分配的对象的内存

  2. Native:
    从C或c++代码中分配的对象的内存
    即使你没有在app中使用c++,你可能会看到一些本地内存,因为Android框架使用Native内存来处理各种任务,比如处理图像资产和其他图形——即使你写的代码是Java或Kotlin

  3. Graphics:
    用于图形缓冲区队列的内存用于显示屏幕上的像素,包括GL表面、GL纹理等
    (注意,这是与CPU共享的内存,而不是专用的GPU内存)

  4. Stack:
    在你的应用程序中,Native和Java栈使用的内存
    这通常与你的应用程序运行的线程数有关

  5. Code:
    您的应用程序用于代码和资源的内存,如dex字节码,优化或编译的dex代码

  6. Other:
    应用程序使用的内存,系统不确定如何分类

  7. Allocated:
    应用程序分配的Java/Kotlin对象的数量。这并不计算用C或c++分配的对象

2.分析ImageView操作以及内存的关系

2.1.前提条件

拥有APP主页面,MainActivity

拥有ImageView测试页面,ImgActivity;ImgActivity的布局文件中有个未设置图片的imageView。我们将通过按钮动态的设置图片,来看一下MEMORY的变化。

我们图片的大小:
vehicle_1:1065*1440 PNG (32-bit color)1.22MB

2.2.测试开始

在这里插入图片描述

  1. 启动我们测试页面,ImgActivity
  2. 设置图片
imageView.setImageResource(R.mipmap.vehicle_1);
  1. 点击按钮通过代码回收ImageView

方法1:

                imageView.setImageDrawable(null);
                imageView = null;

方法2:从父布局移除当前对象

                if (ll != null && imageView != null) {
                    ll.removeView(imageView);
                    imageView = null;
                }
  1. 强制垃圾回收

  2. 关闭当前页面

结论:
如上两种方法都可以达到回收ImageView内存占用的目的。

2.3.我们有必要在应用内调用GC吗?

因为JVM会控制GC哦,我们调用System.gc()也可能仅仅是提醒JVM去回收,正常来讲是不需要我们调用的。

3.可以回收ImageView的bitmap吗

    public void releaseImageViewResouce(ImageView imageView) {
        if (imageView == null)
            return;
        Drawable drawable = imageView.getDrawable();
        if (drawable != null && drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            Bitmap bitmap = bitmapDrawable.getBitmap();
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
            }
        }
    }

在调用这个方法后,重新进入Activity再调用 imageView.setImageResource(R.mipmap.vehicle_1); 偶现异常:
Canvas: trying to use a recycled bitmap android.graphics.Bitmap@18236ae

原因是:Bitmap被recycle了,但是又被复用了。

这是因为虽然你已经将bitmap.recycle() ,但是进程并不知道,GC没有来得及回收Bitmap@18236ae

结论:bitmap.recycle()是可以用于回收bitmap的,但是请谨慎使用,bitmap对象是否已经recycle()需要在使用前判断。

4.ImageView的加载方式

imageView.setImageDrawable(getDrawable(R.mipmap.vehicle_1));

内存占用 ≈ 13.2MB

    <ImageView
        android:src="@mipmap/vehicle_1"
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="300dp" />

内存占用 ≈ 5.9MB

     Glide.with(this)
          .load(R.mipmap.vehicle_1)
          .into(new SimpleTarget<Drawable>() {
                @Override
                public void onResourceReady(@NonNull Drawable resource, 
                											@Nullable Transition<? super Drawable> transition) {
                    imageView.setImageDrawable(resource);
                }
          });

内存占用 ≈ 5.9MB

Glide.with(this).load(R.mipmap.vehicle_1).into(imageView);

内存占用 ≈ 2.3MB

…所以呢,最好使用第三方图片加载框架,因为他们已经做好了图片的优化和压缩。

明明就一张本地图片,为什么会有这种区别呢?

因为图片原本的大小和内存中的大小无关。

1.22MB 是本地图片的大小。但是内存中的大小实际上是:分辨率*像素点的大小。
完全跟图片大小无关(与图片格式png、jpg也无关)

Glide等框架都是通过,降低分辨率或者修改像素点格式,优化了内存中的占用。

注:实际上内存大小还受一些其他因素的影响,这里为了易懂,如此描述。

总结

加载的时候,无论是否是本地图片,最好使用第三方库加载,节约内存

Glide.with(this).load(R.mipmap.vehicle_1).into(imageView);

回收的时候,最好将ImageView置空,因为无引用,GC更容易回收

                imageView.setImageDrawable(null);
                imageView = null;

欢迎留言指教

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风徐来辽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值