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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/su749520/article/details/81633966

1. 内存泄露现象

现象原因

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

2. Android Profiler工具复现现象

2.1 打开 Android Profiler分析

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

打开

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

选择进程

2.3 查看堆栈

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

dump文件

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后结果

优化后

猜你喜欢

转载自blog.csdn.net/su749520/article/details/81633966