`
enuoCM
  • 浏览: 20860 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

内存泄漏之TextLine.recycle

阅读更多
Issue: https://code.google.com/p/android/issues/detail?id=59310

android.text.TextLine has memory leak on mSpanned and SpanSet.

使用下面的工具类移除泄漏:
public class TextLineRecycler {
    private static Field sCached;
    private static Field sCharacterStyleSpanSet;
    private static Field sMetricAffectingSpanSpanSet;
    private static Field sReplacementSpanSpanSet;
    private static Field sSpans;
    private static Field sSpanned;
    private static Field sText;

    static {
        try {
            Class clazz = Class.forName("android.text.TextLine");
            sCached = clazz.getDeclaredField("sCached");
            sSpanned = clazz.getDeclaredField("mSpanned");
            sText = clazz.getDeclaredField("mText");
            sCached.setAccessible(true);
            sSpanned.setAccessible(true);
            sText.setAccessible(true);
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                sCharacterStyleSpanSet = clazz.getDeclaredField("mCharacterStyleSpanSet");
                sMetricAffectingSpanSpanSet = clazz.getDeclaredField("mMetricAffectingSpanSpanSet");
                sReplacementSpanSpanSet = clazz.getDeclaredField("mReplacementSpanSpanSet");
                Class spanSetClass = Class.forName("android.text.SpanSet");
                sSpans = spanSetClass.getDeclaredField("spans");
                sCharacterStyleSpanSet.setAccessible(true);
                sMetricAffectingSpanSpanSet.setAccessible(true);
                sReplacementSpanSpanSet.setAccessible(true);
                sSpans.setAccessible(true);
            }
        } catch (Exception e) {
            Log.e("TextLineRecycler", "", e);
        }
    }

    /**
     * recycle system TextLine
     */
    public static void recycle() {
        try {
            Object cached = sCached.get(null);
            int length = Array.getLength(cached);
            if (cached != null) {
                synchronized (cached) {
                    for (int i = 0; i < length; i++) {
                        Object textLine = Array.get(cached, i);
                        if (textLine != null) {
                            Object text = sText.get(textLine);
                            // mText has been recycled, recycle mSpanned and other SpanSet here
                            if (null == text && null != sSpanned.get(textLine)) {
                                sSpanned.set(textLine, null);
                                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                                    recycleSpan(sCharacterStyleSpanSet, textLine);
                                    recycleSpan(sMetricAffectingSpanSpanSet, textLine);
                                    recycleSpan(sReplacementSpanSpanSet, textLine);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            Log.e("TextLineRecycler", "", e);
        }
    }

    private static <T extends CharacterStyle> void recycleSpan(Field field, Object textLine)
            throws IllegalArgumentException, IllegalAccessException {
        Object spanSet = field.get(textLine);
        T[] spans = (T[]) TextLineRecycler.sSpans.get(spanSet);
        if (spans != null) {
            for (int i = 0; i < spans.length; i++) {
                spans[i] = null;
            }
        }
    }
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics