androidexceptionandroid-resourcesandroid-stylestypedarray

Testing TypedArray recycle() does not throw RuntimeException


I tested TypedArray recycle with this code, expecting to get a runtime exception based on the documentation, but I did not get one.

recycle

added in API level 1
void recycle () Recycles the TypedArray, to be re-used by a later caller. After calling this function you must not ever touch the typed array again.

Throws RuntimeException if the TypedArray has already been recycled.

    public TimePickerPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TimePickerPreference, 0, 0);
        initTimePickerPreference(a);
        a.recycle();
    }
    protected void initTimePickerPreference(TypedArray a) {

        if (a != null)
            try {
                setTitle(a.getString(R.styleable.TimePickerPreference_android_title));
                mSummary = a.getString(R.styleable.TimePickerPreference_android_summary);
                mDefaultValue = a.getString(R.styleable.TimePickerPreference_android_defaultValue);
            } finally {
                a.recycle();
            }

    ...
    }

I traced the code with the Android Studio debugger and it went through both a.recycle() calls, while in variables pane a was not made null

The reason I made this test is because I was not 100% sure if it was OK to call a.recycle() in a different scope from where a was created.

I went further and duplicated the recycle call

    public TimePickerPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TimePickerPreference, 0, 0);
        initTimePickerPreference(a);
        a.recycle();
        a.recycle();
    }
    protected void initTimePickerPreference(TypedArray a) {

        if (a != null)
            try {
                setTitle(a.getString(R.styleable.TimePickerPreference_android_title));
                mSummary = a.getString(R.styleable.TimePickerPreference_android_summary);
                mDefaultValue = a.getString(R.styleable.TimePickerPreference_android_defaultValue);
            } finally {
                a.recycle();
                a.recycle();
            }

    ...
    }

Still no RunTimeException.

Is this a bug?
I ran it on AVD emulated device with Android IceCreamSandwich version (API 15).


Solution

  • Here's the implementation of TypedArray#recycle() for API 15:

     public void recycle() {
         synchronized (mResources.mTmpValue) {
             TypedArray cached = mResources.mCachedStyledAttributes;
             if (cached == null || cached.mData.length < mData.length) {
                 mXml = null;
                 mResources.mCachedStyledAttributes = this;
             }
         }
     }
    

    Here's the implementation for API 25:

    public void recycle() {
        if (mRecycled) {
            throw new RuntimeException(toString() + " recycled twice!");
        }
        mRecycled = true;
        // These may have been set by the client.
        mXml = null;
        mTheme = null;
        mAssets = null;
        mResources.mTypedArrayPool.release(this);
    }
    

    Obviously, docs state the implementation of the latest API, and you are running your app with API 15.