美文网首页Android开发经验谈基于Weex的跨端方案Android开发
基于Weex的跨多端融合方案(五)——加载GIF图时宽高获取异常

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

作者: Meteorwizard | 来源:发表于2019-06-12 21:38 被阅读4次

    前言

    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,不然依然无法正常显示……

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/syglfctx.html