[内存泄露]Android Profiler分析实例-Handle

1. 内存泄露现象

[内存泄露]Android Profiler分析实例-Handle_第1张图片

相同的 Controller 类型控件,红框中在 Android Profiler 显示大内存,且发现对象不断创建没释放

2. Android Profiler工具复现现象

2.1 打开 Android Profiler分析

下图标准了2个方法,哪个习惯用哪个

[内存泄露]Android Profiler分析实例-Handle_第2张图片

2.2 选择一个需要监控内存泄露的进程

[内存泄露]Android Profiler分析实例-Handle_第3张图片

2.3 查看堆栈

主要通过使用dump查看各个代码类的堆栈信息,查找大内存的类对象。

[内存泄露]Android Profiler分析实例-Handle_第4张图片

3. 分析

从内存泄露现象发现,对象没有被回收

查看问题代码

package com.lava.powersave.fuelguage;

import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.util.Log;

import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.events.OnDestroy;

import com.lava.powersave.LavaPowerSaveConstant;
import com.lava.powersave.LavaPowerSaveUtil;

public class LavaPowerSavePreferenceController extends AbstractPreferenceController implements OnPreferenceClickListener, OnDestroy {

    private static final String TAG = LavaPowerSavePreferenceController.class.getSimpleName();

    private static final String KEY_LAVA_POWER_SAVE = "key_lava_power_save";

    private static final int MSG_UPDATE_SWITCH = 0;
    private static final long WAIT_FOR_SWITCH_ANIM = 500;

    private static final int MSG_UPDATE_CLICKABLE = 1;
    private static final long WAIT_FOR_CLICKABLE = 3000;

    private Context mContext;

    private SwitchPreference mBatterySaverPref;

    public LavaPowerSavePreferenceController(Context context) {
        super(context);

        this.mContext = context;
        mContext.getContentResolver().registerContentObserver(Settings.System.getUriFor(LavaPowerSaveConstant.KEY_POWER_SAVE_MODE), false, mPowerSaveObserver);
    }

    @Override
    public void onDestroy() {
        mContext.getContentResolver().unregisterContentObserver(mPowerSaveObserver);
    }

    private final Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_UPDATE_SWITCH:
                mBatterySaverPref.setChecked(LavaPowerSaveUtil.isLavaPowerSaveMode(mContext));
                break;
            case MSG_UPDATE_CLICKABLE:
                mBatterySaverPref.setEnabled(true);
                break;
            }
        }

    };

    @Override
    public boolean isAvailable() {
        return LavaPowerSaveConstant.LAVA_POWER_SAVE ? true : false;
    }

    @Override
    public String getPreferenceKey() {
        return KEY_LAVA_POWER_SAVE;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mBatterySaverPref = (SwitchPreference) screen.findPreference(KEY_LAVA_POWER_SAVE);

        mBatterySaverPref.setOnPreferenceClickListener(this);
    }

    @Override
    public void updateState(Preference preference) {
        mHandler.sendEmptyMessage(MSG_UPDATE_SWITCH);
    }

    @Override
    public boolean onPreferenceClick(Preference preference) {
        mBatterySaverPref.setEnabled(false);
        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_CLICKABLE, WAIT_FOR_CLICKABLE);

        LavaPowerSaveUtil.startLavaPowerSaveMode(mContext, mBatterySaverPref.isChecked());
        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_SWITCH, WAIT_FOR_SWITCH_ANIM);
        return true;
    }

    private ContentObserver mPowerSaveObserver = new ContentObserver(new Handler()) {

        public void onChange(boolean selfChange) {
            mHandler.sendEmptyMessage(MSG_UPDATE_SWITCH);
        }

    };

}

发现上述Handle的使用存在问题,注释掉Handle的方法,调用发现内存泄露问题消失

4. 解决非静态内部类导致的内存泄露

具体如下,本文主要介绍Android Profiler分析实例工具使用

优化了Handle的回收,防止内存泄露

package com.lava.powersave.fuelguage;

import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.util.Log;

import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.events.OnDestroy;

import com.lava.powersave.LavaPowerSaveConstant;
import com.lava.powersave.LavaPowerSaveUtil;

public class LavaPowerSavePreferenceController extends AbstractPreferenceController implements OnPreferenceClickListener, OnDestroy {

    private static final String TAG = LavaPowerSavePreferenceController.class.getSimpleName();

    private static final String KEY_LAVA_POWER_SAVE = "key_lava_power_save";

    private static final int MSG_UPDATE_SWITCH = 0;
    private static final long WAIT_FOR_SWITCH_ANIM = 500;

    private static final int MSG_UPDATE_CLICKABLE = 1;
    private static final long WAIT_FOR_CLICKABLE = 3000;

    private Context mContext;
    private final H mHandler = new H();
    private SwitchPreference mBatterySaverPref;

    public LavaPowerSavePreferenceController(Context context) {
        super(context);

        this.mContext = context;
        mContext.getContentResolver().registerContentObserver(Settings.System.getUriFor(LavaPowerSaveConstant.KEY_POWER_SAVE_MODE), false, mPowerSaveObserver);
    }

    @Override
    public void onDestroy() {
        mContext.getContentResolver().unregisterContentObserver(mPowerSaveObserver);
    }

    private final class H extends Handler {
        private H() {
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE_SWITCH:
                    mBatterySaverPref.setChecked(LavaPowerSaveUtil.isLavaPowerSaveMode(mContext));
                    break;
                case MSG_UPDATE_CLICKABLE:
                    mBatterySaverPref.setEnabled(true);
                    break;
            }
        }
    }

    @Override
    public boolean isAvailable() {
        return LavaPowerSaveConstant.LAVA_POWER_SAVE ? true : false;
    }

    @Override
    public String getPreferenceKey() {
        return KEY_LAVA_POWER_SAVE;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mBatterySaverPref = (SwitchPreference) screen.findPreference(KEY_LAVA_POWER_SAVE);

        mBatterySaverPref.setOnPreferenceClickListener(this);
    }

    @Override
    public void updateState(Preference preference) {
        mHandler.sendEmptyMessage(MSG_UPDATE_SWITCH);
    }

    @Override
    public boolean onPreferenceClick(Preference preference) {
        mBatterySaverPref.setEnabled(false);
        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_CLICKABLE, WAIT_FOR_CLICKABLE);

        LavaPowerSaveUtil.startLavaPowerSaveMode(mContext, mBatterySaverPref.isChecked());
        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_SWITCH, WAIT_FOR_SWITCH_ANIM);
        return true;
    }

    private ContentObserver mPowerSaveObserver = new ContentObserver(new Handler()) {

        public void onChange(boolean selfChange) {
            mHandler.sendEmptyMessage(MSG_UPDATE_SWITCH);
        }

    };

}

5.优化后结果

重新dump后结果

[内存泄露]Android Profiler分析实例-Handle_第5张图片

你可能感兴趣的:(性能优化)