App有内存泄漏就是埋了一颗定时炸弹, 累积多了终将导致OOM. 下面列举一些常见导致内存泄漏的代码.
未注销导致的内存泄漏
使用了广播, EventBus等等, 会导致Activity无法被GC回收
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
EventBus.getDefault().register(this);
}
@Subscribe
public void onEvent(MessageEvent msg) {
}
@Override
protected void onDestroy() {
super.onDestroy();
//未移除注册的EventBus
// EventBus.getDefault().unregister(this);
}
非静态内部类使用不当导致的内存泄漏
非静态内部类会持有外部类引用, 如果Activity中包含了静态的内部类成员就会导致内存泄漏
private static InnerClass mInnerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
mInnerClass = new InnerClass();
}
//非静态内部类持有外部类引用
public class InnerClass {
private String msg;
public InnerClass() {
}
}
匿名类使用不当导致的内存泄漏
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
//匿名类持有外部类引用
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}.execute();
}
工具类使用不当导致的内存泄漏
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
String s = Util.getInstance(this).doSomething();
}
public class Util {
private volatile static Util instance;
private static Context mContext;
private Util(Context context) {
mContext = context;
}
//传进来的context被静态持有
public static Util getInstance(Context context) {
if (instance == null) {
synchronized (Util.class) {
if (instance == null) {
instance = new Util(context);
}
}
}
return instance;
}
public static String doSomething() {
String string = mContext.getResources().getString(R.string.app_name);
return string;
}
}
写Util的时需要Context的时候, 判断一下, 如果可以用ApplicationContext优先使用.
可以用ApplicationContext的情况下在Application里面加上一个getInstance()方法, 就不用传Context进来了.
public class App extends Application {
private static App instance;
public static App getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
instance = this;
}
}
线程使用不当导致的内存泄漏
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
//Activity实例被Runnable持有, Runnable传入l一个异步线程,
// 此线程和此Acitivity生命周期不一致的时候,就造成了Activity的泄露。
new Thread(new Runnable() {
@Override
public void run() {
while (true) ;
}
}).start();
}
Handle使用不当导致的内存泄漏
private Handler mLeakyHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
//Handler 为非静态内部类,它会持有外部类的引用
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() {
//doSomething
}
}, 1000 * 20);
}
静态集合使用不当导致的内存泄漏
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//静态集合没有移除元素
// ActivityCollector.removeActivity(this);
}
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<Activity>();
public static void addActivity(Activity activity) {
activities.add(activity);
}
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
}
使用弱引用避免内存泄漏
在 Activity 中避免使用非静态内部类,比如上面我们将 Handler 声明为静态的,则其存活期跟 Activity 的生命周期就无关了。同时通过弱引用的方式引入 Activity,避免直接将 Activity 作为 context 传进去
public class WeakReferenceActivity extends AppCompatActivity {
//将 Handler 声明为静态 没有了Activity的引用, 无法直接引用其变量或方法,
// 使用弱引用WeakReference来解决这个问题
private static class DBHandler extends Handler {
//弱引用, 而不是使用外部类this或者传进来
private final WeakReference<WeakReferenceActivity> mActivity;
public DBHandler(WeakReferenceActivity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
WeakReferenceActivity activity = mActivity.get();
if (activity != null) {
Toast.makeText(activity, "what: " + msg.what, Toast.LENGTH_SHORT).show();
}
}
}
private final DBHandler mHandler = new DBHandler(this);
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() {
Toast.makeText(App.getInstance(), "sRunnable run()", Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_weak_reference);
mHandler.postDelayed(sRunnable, 1000 * 20);
}
public void onClick(View view) {
mHandler.sendEmptyMessage(new Random().nextInt(10));
}
}
LeakCanary的使用
- build.gradle dependencies{…}添加
//https://github.com/square/leakcanary
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
- Application配置
public class App extends Application {
private static App instance;
private static RefWatcher sRefWatcher;
public static RefWatcher getRefWatcher() {
return sRefWatcher;
}
public static App getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
sRefWatcher = LeakCanary.install(this);
// Normal app init code...
instance = this;
}
}
- AndroidManifest.xml
<application
android:name="yourApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
检测Fragment内存泄漏
public class LeakFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_common, container, false);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
while (true) ;
}
}).start();
}
@Override
public void onDestroy() {
super.onDestroy();
//onDestroy中添加
App.getRefWatcher().watch(this);
}
}