1. 程式人生 > >setImageResource、setImageDrawable和setImageBitmap的區別

setImageResource、setImageDrawable和setImageBitmap的區別

最近遇到ImageView控制元件設定的圖片延遲才顯示的問題(雖然最終發現原因是圖片是全透明的)。

順勢跟蹤了一下給ImageView設定圖片的原始碼。

以下分析都是基於Android8.0

setImageResource

原始碼中對該介面的註釋:

    /**
     * Sets a drawable as the content of this ImageView.
     * <p class="note">This does Bitmap reading and decoding on the UI
     * thread, which can cause a latency hiccup.  If that's a concern,
     * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
     * {@link #setImageBitmap(android.graphics.Bitmap)} and
     * {@link android.graphics.BitmapFactory} instead.</p>
     *
     * @param resId the resource identifier of the drawable
     *
     * @attr ref android.R.styleable#ImageView_src
     */
    @android.view.RemotableViewMethod(asyncImpl="setImageResourceAsync")
    public void setImageResource(@DrawableRes int resId) {
        // The resource configuration may have changed, so we should always
        // try to load the resource even if the resId hasn't changed.
       .....
    }

在UI執行緒中處理bitmap,這可能造成主執行緒的延遲(如導致Activity啟動延遲等情況)。

可以考慮使用setImageDrawable(Drawable)或setImageBitmap(Bitmap)代替。

setImageDrawable

    /**
     * Sets a drawable as the content of this ImageView.
     *
     * @param drawable the Drawable to set, or {@code null} to clear the
     *                 content
     */
    public void setImageDrawable(@Nullable Drawable drawable) {
        if (mDrawable != drawable) {
            mResource = 0;
            mUri = null;

            final int oldWidth = mDrawableWidth;
            final int oldHeight = mDrawableHeight;

            updateDrawable(drawable);

            if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
                requestLayout();
            }
            invalidate();
        }
    }

setImageDrawable(null)可以清除一個ImageView控制元件設定的圖片。

setImageBitmap

    /**
     * Sets a Bitmap as the content of this ImageView.
     *
     * @param bm The bitmap to set
     */
    @android.view.RemotableViewMethod
    public void setImageBitmap(Bitmap bm) {
        // Hacky fix to force setImageDrawable to do a full setImageDrawable
        // instead of doing an object reference comparison
        mDrawable = null;
        if (mRecycleableBitmapDrawable == null) {
            mRecycleableBitmapDrawable = new BitmapDrawable(mContext.getResources(), bm);
        } else {
            mRecycleableBitmapDrawable.setBitmap(bm);
        }
        setImageDrawable(mRecycleableBitmapDrawable);
    }

setImageBitmap實際還是呼叫的setImageDrawable,但是強制setImageDrawble執行完整的setImageDrawable而不是做物件引用比較。setImageBitmap將Bitmap物件封裝成Drawable物件,

setImageBitmap和setImageDrawable的區別

參考自https://blog.csdn.net/zhaoyazhi2129/article/details/32080827

同樣的佈局檔案,小解析度手機:

  1. 使用setImageBitmap設定時,顯示如下:

  2. 使用setImageResource設定時,顯示正常:

原因:

setImageResource(id)會根據裝置解析度進行圖片大小縮放適配。

setImageBitmap(BitmapFactory.decodeResource(res, id))大小需要手動調。

如果提供了完整的各種解析度下的圖片,兩種方法沒有區別。

總結

綜合來看,setImageDrawable是最省記憶體最高效的,如果擔心圖片過大或者圖片過多影響記憶體和載入效率,可以自己解析圖片然後通過呼叫setImageDrawable方法進行設定。