TypeArray为什么要recycle()

390 阅读2分钟

在Android开发过程中,使用到自定义属性的时候,经常到使用TypeArray,每次用完都要使用typeArray.recycle(),这句话的具体含义是什么?

先说答案:

获取typeArray时先会去TypeArray对象池中拿TypeArray对象,拿不到便会创建一个TypeArray对象,使用完再放回TypeArray对象池里,典型的享元模式,避免因频繁创建、销毁TypeArray对象造成内存抖动

再慢慢看源码:

  1. 先从TypeArray的获取,context.obtainStyledAttributes说起:

一步一步追源码:

context#obtainStyledAttributes

@NonNull
public final TypedArray obtainStyledAttributes(
        @Nullable AttributeSet set, @NonNull @StyleableRes int[] attrs) {
    return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
}

getTheme的返回值是Resources的内部类

Resrouces#obtainStyledAttributes

@NonNull
public TypedArray obtainStyledAttributes(@Nullable AttributeSet set,
        @NonNull @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
        @StyleRes int defStyleRes) {
    return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
}

Resources#obtainStyledAttributes

@NonNull
TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
        AttributeSet set,
        @StyleableRes int[] attrs,
        @AttrRes int defStyleAttr,
        @StyleRes int defStyleRes) {
    synchronized (mKey) {
        final int len = attrs.length;
        // 从TypedArray的obtain方法中获取,然后返回
        final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
        //xxxxxxx
        return array;
    }
}

咱们直接看最重要的一句,这里拿到了TypeArray对象 这里捋一下思路,所有的内容都是一路调用,最后将TypedArray.obtain中的typeArray返回

TypedArray#obtain

static TypedArray obtain(Resources res, int len) {
    TypedArray attrs = res.mTypedArrayPool.acquire();
    if (attrs == null) {
        attrs = new TypedArray(res);
    }
    //xxxx
    return attrs;
}

该方法中先从mTypeArrayPool中取,取不到,就自己创建一个,看名字更像是一个对象池 从res.mTypedArrayPool可以看出mTypeArrayPool是Resources类的成员变量 记住这里的acquire方法,下面有用

Resrouces#mTypedArrayPool

// Pool of TypedArrays targeted to this Resources object.
@UnsupportedAppUsage
final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);

由注释证明了猜想,mTypeArrayPool确实是TypeArray对象池,查看下SynchronizedPool Pool#SynchronizedPool

public static class SynchronizedPool<T> extends SimplePool<T> {
    private final Object mLock = new Object();
    public SynchronizedPool(int maxPoolSize) {
        super(maxPoolSize);
    }
​
    @Override
    public T acquire() {
        synchronized (mLock) {
            return super.acquire();
        }
    }
​
    @Override
    public boolean release(@NonNull T element) {
        synchronized (mLock) {
            return super.release(element);
        }
    }
}

最终的typeArray就是从这里(res.mTypedArrayPool.acquire()最终调用的这里)取的,看下父类SimplePool

public static class SimplePool<T> implements Pool<T> {
        @Override
        @SuppressWarnings("unchecked")
        public T acquire() {
            if (mPoolSize > 0) {
                final int lastPooledIndex = mPoolSize - 1;
                T instance = (T) mPool[lastPooledIndex];
                mPool[lastPooledIndex] = null;
                mPoolSize--;
                return instance;
            }
            return null;
        }
​
        // mPoolSize是初始化大小5,mPool.length是当前池子的大小
        @Override
        public boolean release(@NonNull T instance) {
            if (isInPool(instance)) {
                throw new IllegalStateException("Already in the pool!");
            }
            if (mPoolSize < mPool.length) {
                mPool[mPoolSize] = instance;
                mPoolSize++;
                return true;
            }
            return false;
        }
}

直接从变量池里取的TypeArray对象。

那么typeArray.recycle(),调用的什么呢,直接点进去发现调用的是

TypeArray#recycle()

public void recycle() {
    //xxx
    //将改变放回对象池
    mResources.mTypedArrayPool.release(this);
}

综上:获取typeArray时先会去对象池(大小为5)中拿TypeArray对象,拿不到便会创建一个TypeArray对象,使用完再放回对象池里,典型的享元模式,避免因频繁创建、销毁TypeArray对象造成内存抖动