Android开发经验谈基于Weex的跨端方案Android开发

基于Weex的跨多端融合方案(五)——加载GIF图时宽高获取异常

2019-06-12  本文已影响4人  Meteorwizard

前言

Weex是目前跨端方案中相对比较成熟的一个,但是开源版本的Weex在实际使用过程中还是碰到不少问题,今天就来说说一个最近碰到的Android端有关于图片加载的坑。

Weex的image标签在一般的使用场景下都是预先指定宽高的,然而在一些特殊场景下,我们需要根据网络图片的宽高来动态指定image标签的宽高。于是乎,坑就来了,在加载常规的png/jpg图片时,一切都是正常的,但是在加载gif时,就会出现无法正常获取宽高的问题。

Weex官方的处理速度一直很捉急,那么只能从源码入手一步步自己排查问题。

问题排查

Weex提供了IWXImgLoaderAdapter接口让用户自己可以自定义图片加载库,我们这边则使用了Glide来加载图片。

public interface IWXImgLoaderAdapter {
    void setImage(String var1, ImageView var2, WXImageQuality var3, WXImageStrategy var4);
}

在setImage方法中自定义图片加载:

Glide.with(context).load(temp).listener(new RequestListener<String, GlideDrawable>() {
                        @Override
                        public boolean onException(Exception e, String model, Target<GlideDrawable> target,
                                                   boolean isFirstResource) {
                            if (strategy != null && strategy.getImageListener() != null) {
                                strategy.getImageListener().onImageFinish(url, view, false, null);
                            }
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target,
                                                       boolean isFromMemoryCache, boolean isFirstResource) {
                            if (strategy != null && strategy.getImageListener() != null) {
                                strategy.getImageListener().onImageFinish(url, view, true, null);
                            }
                            return false;
                        }
                    }).into(view);

其中WXImageStrategy的ImageListener接口最终在com.taobao.weex.ui.component.WXImage的setRemoteSrc被实现。

public class WXImageStrategy {
    /** @deprecated */
    @Deprecated
    public boolean isClipping;
    public boolean isSharpen;
    public int blurRadius;
    public String placeHolder;
    WXImageStrategy.ImageListener imageListener;

    public WXImageStrategy() {
    }

    public WXImageStrategy.ImageListener getImageListener() {
        return this.imageListener;
    }

    public void setImageListener(WXImageStrategy.ImageListener imageListener) {
        this.imageListener = imageListener;
    }

    public interface ImageListener {
        void onImageFinish(String var1, ImageView var2, boolean var3, Map var4);
    }
}
private void setRemoteSrc(Uri rewrited, int blurRadius) {
        WXImageStrategy imageStrategy = new WXImageStrategy();
        imageStrategy.isClipping = true;
        WXImageSharpen imageSharpen = this.getDomObject().getAttrs().getImageSharpen();
        imageStrategy.isSharpen = imageSharpen == WXImageSharpen.SHARPEN;
        imageStrategy.blurRadius = Math.max(0, blurRadius);
        this.mBlurRadius = blurRadius;
        imageStrategy.setImageListener(new ImageListener() {
            public void onImageFinish(String url, ImageView imageView, boolean result, Map extra) {
                if (WXImage.this.getDomObject() != null && WXImage.this.getDomObject().getEvents().contains("load")) {
                    Map<String, Object> params = new HashMap();
                    Map<String, Object> size = new HashMap(2);
                    if (imageView != null && imageView instanceof WXImage.Measurable) {
                        size.put("naturalWidth", ((WXImage.Measurable)imageView).getNaturalWidth());
                        size.put("naturalHeight", ((WXImage.Measurable)imageView).getNaturalHeight());
                    } else {
                        size.put("naturalWidth", 0);
                        size.put("naturalHeight", 0);
                    }

                    if (WXImage.this.getDomObject() != null && WXImage.this.containsEvent("load")) {
                        params.put("success", result);
                        params.put("size", size);
                        WXImage.this.fireEvent("load", params);
                    }
                }

            }
        });
        String placeholder = null;
        if (this.getDomObject().getAttrs().containsKey("placeholder")) {
            placeholder = (String)this.getDomObject().getAttrs().get("placeholder");
        } else if (this.getDomObject().getAttrs().containsKey("placeHolder")) {
            placeholder = (String)this.getDomObject().getAttrs().get("placeHolder");
        }

        if (!TextUtils.isEmpty(placeholder)) {
            imageStrategy.placeHolder = this.getInstance().rewriteUri(Uri.parse(placeholder), "image").toString();
        }

        IWXImgLoaderAdapter imgLoaderAdapter = this.getInstance().getImgLoaderAdapter();
        if (imgLoaderAdapter != null) {
            imgLoaderAdapter.setImage(rewrited.toString(), (ImageView)this.getHostView(), this.getDomObject().getAttrs().getImageQuality(), imageStrategy);
        }

    }

在setRemoteSrc方法中通过com.taobao.weex.ui.view.WXImageView的getNaturalWidth以及getNaturalHeight方法来获取最终的宽高,然后问题就是出来这两个方法的实现上,我们继续看:

 public int getNaturalWidth() {
        Drawable drawable = this.getDrawable();
        if (drawable != null) {
            if (drawable instanceof ImageDrawable) {
                return ((ImageDrawable)drawable).getBitmapWidth();
            }

            if (drawable instanceof BitmapDrawable) {
                Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();
                if (bitmap != null) {
                    return bitmap.getWidth();
                }

                WXLogUtils.w("WXImageView", "Bitmap on " + drawable.toString() + " is null");
            } else {
                WXLogUtils.w("WXImageView", "Not supported drawable type: " + drawable.getClass().getSimpleName());
            }
        }

        return -1;
    }

com.taobao.weex.ui.view.WXImageView实际是继承自android.widget.ImageView,在getNaturalWidth以及getNaturalHeight中通过拿到ImageView的Drawable来拿到宽高,然而Gif格式的图片拿到的却是GifDrawable。所以最终自然就没办法拿到实际宽高了。

解决方案

  1. 在不修改Weex源码前提下,需要先用Glide将Gif图加载成File,然后通过判断文件头或者调用系统的BitmapFactory.Options类的outMimeType等方式获取图片宽高设置给image,然后再次调用glide将图片设置到最终的ImageView中。

  2. 修改Weex的com.taobao.weex.ui.view.WXImageView类中的getNaturalWidth以及getNaturalHeight方法,当发现是GifDrawable时候,调用Drawable类的getIntrinsicWidth以及getIntrinsicHeight来获取宽高。

PS

Weex的image标签如果需要动态设置宽高还有一个坑,就还是需要预先给image标签设置一个初试宽高,通常会设置1px,不然依然无法正常显示……

上一篇下一篇

猜你喜欢

热点阅读