Android Weex 图片适配器 ImageAdapter 优化

Weex Android 图片加载优化

      Android的weex界面中的图片加载是通过ImageAdapterl类来加载,阿里官方的例子中使用了Picasso图片加载框架来加载图片(鄙视他们),我们项目使用更好更优秀的Google官方推荐的Glide图片加载框架来为weex界面加载图片(一个隐藏的优化意见->使用Glide框架),所以以下优化方案都是针对Glide的优化。
 

一、优化weex图片加载速度

     weex加载的图片大小不一,有的很大的图片会加载缓慢,所以可以使用缩略图,让weex先加载出模糊的缩略图,再加载出清晰的图片,Glide的缩略图加载如下
 

//使用.thumbnail(0.2f) 0.2是原图大小的倍数既缩小5倍质量 

Glide.with(context).load(url).thumbnail(0.2f).into(view);

二、weex图片加载内存优化

      图片在加载完成后,会占用很多内存,当weex界面有大量大图片时,会消耗很多内存,造成界面卡顿、图片加载失败,甚至是app奔溃。因此要在内存优化方面做的更好有以下方法。
 

1、app申请更大内存(慎用)

       安卓系统会给app申请固定的内存,对于每个应用都有内存使用的限制,并不是还剩多少内存就可以用多少内存,机器的内存限制,可以在/system/build.prop文件中配置的。所以有时候你会看到手机还有内存,app就已经内存不足闪退了。我们可以在app中的AndroidManifest.xml设置largeHeap="true"以增加内存的申请量。但不是系统有多少内存就可以申请多少,而是由手机的dalvik.vm.heapsize限制。
    慎用!作为程序员的我们应该努力减少内存的使用,尽量想回收和复用的方法,而不是想方设法增大内存。当内存很大的时候,每次gc的时间也会长一些,性能会下降的。

2、加载图片资源的释放

     Glide加载weex图片时,Glide.with(context)需要传输一个上下文,不使用application作为context。当context为application时,会把imageView是生命周期延长到整个运行过程中,imageView不能被回收,从而造成OOM异常。传输当前Activity的context,当Activity结束时,glide会自动释放图片资源(glide真强)。

3、按照imageview大小加载图片

      glide本来是自动实现了该优化点,可是weex源码带来的一个坑导致glide不会自动按照view大小加载图片,会加载出原图大小,导致一些大图加载出来占用内存过大,像素点极高,增加了GPU的绘制压力,从而界面卡顿。我们先来看看weex的坑。

wxImage源码

    这是weex中的image标签在sdk中的实现,该方法为加载src

wxImage源码

 

         在该方法中,会生成一个WXImageStrategy的引用,负责存储一些图片的属性如锐化、圆角、图片加载完成的监听器等,也就是说不管你有没有设置这些属性,weex都要给你创建一个,并且要在图片加载完成后触发该监听器。这就无语了,很多weex界面是不需要知道你是否图片加载完成的,多此一举,应该提供一个属性来控制是否监听更合适。这就导致了glide不能直接加载图片,而是需要在加载完成后调用该监听器,则上面的glide加载代码就要通过Target来加载,如下
 

Glide.with(Application.getCurrentActivity()).load(url).thumbnail(0.2f).into(new SimpleTarget<Drawable>(view.getLayoutParams().width,view.getLayoutParams().height) {
                        @Override
                        public void onResourceReady(Drawable resource, @Nullable Transition<? super Drawable> transition) {
                            if (strategy.getImageListener() != null) {
                                strategy.getImageListener().onImageFinish(url, view, true, null);
                            }
                            if (resource.getIntrinsicWidth() >= 4096 || resource.getIntrinsicHeight() >= 4096) {
                                view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
                            }
                            view.setImageDrawable(resource);
                        }
                        @Override
                        public void onLoadFailed(@Nullable Drawable errorDrawable) {
                            super.onLoadFailed(errorDrawable);
                            if (strategy.getImageListener() != null) {
                                strategy.getImageListener().onImageFinish(url, view, false, null);
                            }
                        }
                    });

       这里将into(view)改为into(SimpleTarget<Drawable>(){}),Target的onResourceReady()中可以调动事件的监听。坑就在这里,当glide使用这个方式时,不会根据view的大小自动调整图片大小,会加载出原图大小,当图片特别大的时候就炸了,网上各种教程都有这个坑,因此代码中我在SimpleTarget<Drawable>()中传了view的宽高SimpleTarget<Drawable>(view.getLayoutParams().width,view.getLayoutParams().height),glide会根据该宽高加载图片,从而优化大量内存。

4、超大图导致GPU超频,无法绘制图 mn0片

       在一些手机上会导致该问题,超大图过大,绘制消耗大量资源,最后绘制失败,无法显示图片。由于在Android 4.0以上系统自动开启硬件加速,但是硬件的加速会占有一定的RAM,使用GPU绘制图片,图片又大,导致超频。如果你的应用只是标准的View和Drawable,全局都打开硬件加速,是不会有任何问题的。然而,硬件加速并不支持所有的2D画图的操作,这时开着它,可能会影响到你的自定义控件或者绘画,出现异常等行为。
      因此只要关闭硬件加速即可。硬件加速可以从4个层面进行关闭,分别是app、Activity、Window、View,我们当然不能直接关闭整个app的硬件加速,这样会降低app的响应速度,我们可以在view层面进行关闭,在上一段代码中的view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);便是关闭了imageview的硬件加速,我判断加载出的Drawable resource的宽高,超过4096即关闭硬件加速。
 

5、牺牲图片质量

      这个方法在项目中并没有使用,所以研究不深,观众可以自行选择,该方法会牺牲图片的质量,进行压缩,需要使用的观众可以在Target的回调方法中,将获取的resource进行压缩。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中,图片适配器通常用于在列表视图、网格视图或翻页视图等容器中显示图片适配器负责将图片数据绑定到每个视图中,以便正确显示图片。 以下是一个简单的图片适配器示例: ```java public class ImageAdapter extends BaseAdapter { private Context mContext; private int[] mImageIds; public ImageAdapter(Context context, int[] imageIds) { mContext = context; mImageIds = imageIds; } public int getCount() { return mImageIds.length; } public Object getItem(int position) { return null; } public long getItemId(int position) { return 0; } public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { // 如果没有可重用的视图,则创建一个新的ImageView imageView = new ImageView(mContext); imageView.setLayoutParams(new GridView.LayoutParams(100, 100)); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); } else { // 如果有可重用的视图,则使用它 imageView = (ImageView) convertView; } // 加载图片 imageView.setImageResource(mImageIds[position]); return imageView; } } ``` 在上面的示例中,`ImageAdapter` 继承自 `BaseAdapter` 类,该类是 Android适配器的基类。在构造函数中,传入了一个 `Context` 对象和一个图片 ID 数组,用于初始化适配器。`getCount` 方法返回图片 ID 数组的长度,`getItem` 和 `getItemId` 方法不需要实现,因为它们不会被使用。`getView` 方法是适配器最重要的方法,用于创建或重用视图,并将图片数据绑定到视图中。在该方法中,首先检查是否存在可重用的视图,如果没有,则创建一个新的 `ImageView` 对象,并设置其布局参数和缩放类型。然后,加载并显示适当位置的图片。 请注意,上面的代码中,图片的大小是硬编码的。为了实现更好的图片适配,应该使用 Android 提供的不同尺寸的资源文件夹来存储不同分辨率的图片,例如: ``` res/drawable-mdpi/my_image.png res/drawable-hdpi/my_image.png res/drawable-xhdpi/my_image.png res/drawable-xxhdpi/my_image.png ``` 在加载图片时,适配器将自动根据设备的屏幕密度选择正确的图片

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值