Glide设置了listener却没有回调

Glide不发起请求

问题

接入第三方广告SDK时,使用对方的自渲染信息流广告,在拿到对方图片物料并使用Glide加载网络图片时,Glide设置了listener却没有回调。

广告位的布局如下:

    <FrameLayout
        android:id="@+id/third_ad_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <FrameLayout
            android:id="@+id/ad_panel"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/ad_img_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </FrameLayout>


    </FrameLayout>

物料请求如下:

		val img_view = findViewById<ImageView>(R.id.ad_img_view)
        Glide.with(this@MainActivity)
            .asBitmap()
            .load("imgurl")
            .listener(object : RequestListener<Bitmap> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    isFirstResource: Boolean
                ): Boolean {
                    Log.e("test_url", "onLoadFailed ----")
                    return false
                }

                override fun onResourceReady(
                    resource: Bitmap?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean
                ): Boolean {
                    Log.e("test_url", "onResourceReady ----")
                    return false
                }
            })
            .into(img_view)

期望结果是图片物料展示,且listener打印回调。实际结果是:物料没有展示且任何回调都没有打印。

为什么会出现上面的结果那?

Glide源码分析

我们知道:Glide会在 into 函数中创建一个 request,然后在 onSizeReady 后进行网络请求。上面的问题是没有进行请求,那么肯定是 onSizeReady 没有调用。

// 如果设置了 overrideWidth和overrideHeight,直接执行 onSizeReady
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
      } else { // 否则,查看 ViewTarget.getSize()
        target.getSize(this);
      }

  public void getSize(@NonNull SizeReadyCallback cb) {
    sizeDeterminer.getSize(cb);
  }


  private boolean isSizeValid(int size) {
    return size > 0 || size == LayoutParams.WRAP_CONTENT;
  }

  private void checkCurrentDimens() {
    if (cbs.isEmpty()) {
        return;
    }
    int currentWidth = getViewWidthOrParam();
    int currentHeight = getViewHeightOrParam();
    // 每次绘制回来,都检测一边宽高是否有效
    if (!isSizeValid(currentWidth) || !isSizeValid(currentHeight)) 
        return;
    }
    // 有效的话,则调用 onSizeReady
    notifyCbs(currentWidth, currentHeight);
    
    if (observer.isAlive()) {
        observer.removeOnPreDrawListener(layoutListener);
    }
    layoutListener = null;
  }

  public void getSize(SizeReadyCallback cb) {
    int currentWidth = getViewWidthOrParam();
    int currentHeight = getViewHeightOrParam();
    // 如果宽高都是有效的,则调用 onSizeReady
    if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
        cb.onSizeReady(currentWidth, currentHeight);
    } else {
        if (!cbs.contains(cb)) {
            cbs.add(cb);
        }
        if (layoutListener == null) {
            final ViewTreeObserver observer = view.getViewTreeObserver();
            // 监听view的绘制过程
            layoutListener = new SizeDeterminerLayoutListener(this);
            observer.addOnPreDrawListener(layoutListener);
        }
    }

}

从分析源码可得:当我们使用 into(targetView) 且没有使用 override 设置大小, 如果view的大小无效,则不会进行网络请求。

解决方法

从上面的结论可得,我们只要满足 onSizeReady 触发的条件,就可以实现进行网络请求。

  1. 调用时,使用 override 重写大小。
  2. 将ImageView的宽高设置为 wrap_content或者固定的宽高

可是,在项目中ImageView必须设置为 match_parent,又该如何解决问题那?

其实,上面分析源码的时候,有一个问题没有解决:为什么我们设置的ImageView监听中没有大小那?它不应该和父布局的大小一致吗?如果在测量后,我们能得到想要的大小,问题不就解决了嘛。所以,最终的问题还是view测量的问题。

当我使用下面的布局方式,就解决了问题:

    <FrameLayout
        android:id="@+id/third_ad_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ReleativeLayout
            android:id="@+id/ad_panel"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/ad_img_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </ReleativeLayout>


    </FrameLayout>

FrameLayoutFrameLayoutImageView
match_parent同xml一致同xml一致
wrap_content同父布局一样同父布局一样
FrameLayoutReleativeLayoutImageView
match_parent同xml一致同xml一致
wrap_content同父布局一样同xml一致

从上表可得:ReleativeLayout 在测量时,不会影响子view的测量方式。

所以,在使用ReleativeLayout作为ImageView的父容器时,ImageView测量的大小是window的大小。

上面的逻辑,我是在Android源码中看到的。具体位置:
ReleativeLayout.getChildMeasureSpec()ViewGroup.getChildMeasureSpec(), 可是,Android为什么要这样做那?

ReleativeLayout会测量水平和垂直方向的view,根据相对属性,测量子View的大小。FrameLayout 总是按照左上角的坐标,一层一层的测量view的大小,而LinearLayout是在onMeasure中自己计算每个子view的左上角坐标,然后根据左上角坐标顺序测量子view的大小。所以,ReleativeLayout自己一套测量子view逻辑,而FrameLayout和LinearLayout公用一套测量子View的逻辑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值