文章目录
前言
我们做开发的时候,很容易专注于做功能和业务层面的开发,而忽略APP的性能表现,今天来列出一些做Android开发的时候很容易出现内存泄漏的点。这只针对Java层面的,关于native层的,后续再出博文进行解析。
什么是内存泄漏
从现象看,随着用户不断使用我们的应用程序,内存也在不断增加,如果被引用的内存没有在合适的时机及时地被释放,那么GC机制就无法释放未使用的内存。因此,我们的应用程序的内存会不断增加,直到无法为我们的应用分配更多内存,从而导致OutOfMemoryError,最终导致应用程序崩溃。
GC机制很大程度给予了Java程序员便利,但是Java开发者也需要了解对应的内存机制,否则无法写出高性能&高质量的代码。
1.广播接收器
假如在activity中注册了广播,如果没有在任何地方解除注册的话,广播接收器会引用activity,即使你关闭了这个activity。
public class BroadcastReceiverLeakActivity extends AppCompatActivity {
private BroadcastReceiver broadcastReceiver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
}
private void registerBroadCastReceiver() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//your receiver code goes here!
}
};
registerReceiver(broadcastReceiver, new IntentFilter("SmsMessage.intent.MAIN"));
}
@Override
protected void onStart() {
super.onStart();
registerBroadCastReceiver();
}
@Override
protected void onStop() {
super.onStop();
/*
* Uncomment this line in order to avoid memory leak.
* You need to unregister the broadcast receiver since the broadcast receiver keeps a reference of the activity.
* Now when its time for your Activity to die, the Android framework will call onDestroy() on it
* but the garbage collector will not be able to remove the instance from memory because the broadcastReceiver
* is still holding a strong reference to it.
* */
if(broadcastReceiver != null) {
unregisterReceiver(broadcastReceiver);
}
}
}
怎么解决?
1.记得解除注册广播。
2.假如在oncreate注册的话,当app退出去到后台,再进来的话广播接收器不会再次被注册。
3.所以更好的方式是在activity的onstart方法进行注册,在activity的onstop方法进行解注册。
为什么通常优先选择在 onStop() 中取消注册而不是 onPause()?
活动可见性:onPause() 方法在活动失去焦点但仍部分可见时调用(例如,当另一个活动在其前面启动时)。相反,onStop()
在活动对用户不再可见时调用。在 onStop() 中取消注册可确保您的 BroadcastReceiver
仅在活动完全隐藏或停止时处于活动状态。避免不必要的操作:如果在 onPause() 中取消注册
BroadcastReceiver,则每当活动失去焦点时都会取消注册,即使它仅暂时被其他对话框或系统窗口覆盖。这可能会导致不必要的取消注册和注册操作,可能会影响性能并增加管理接收器状态的复杂性。一致的生命周期管理:通过在 onStop() 中取消注册,可以确保 BroadcastReceiver
的注册和取消注册在互补的生命周期方法中进行。这是一种更清晰的方法,使您的代码更可预测,也更易于其他开发人员理解。但是,在某些特定用例中,在 onPause()
中取消注册可能更合适。例如,如果您的应用程序需要在部分被遮挡时响应某些事件(例如,当对话框打开时根据传入的广播更新UI元素),那么在
onPause() 中取消注册可能是必要的。我们需要根据具体的业务情况进行必要的调整。
2.静态activity或者view的引用
考虑这样的场景:
你定义了一个静态的textview,假如它引用了activity或者view,无论是直接引用还是间接引用,当前的activity在被销毁后无论如何都无法被垃圾回收器回收。
public class StaticReferenceLeakActivity extends AppCompatActivity {
/*
* This is a bad idea!
*/
private static TextView textView;
private static Activity activity;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
textView = findViewById(R.id.activity_text);
textView.setText("Bad Idea!");
activity = this;
}
}
怎么解决?
永远不要把view、activity、context定义为静态的
3.单例类的引用
假如你定义了一个单例类,然后把context传递进去到这个单例类中。
public class SingletonLeakExampleActivity extends AppCompatActivity {
private SingletonSampleClass singletonSampleClass;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Option 1: Do not pass activity context to the Singleton class. Instead pass application Context
*/
singletonSampleClass = SingletonSampleClass.getInstance(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
/*
* Option 2: Unregister the singleton class here i.e. if you pass activity context to the Singleton class,
* then ensure that when the activity is destroyed, the context in the singleton class is set to null.
*/
singletonSampleClass.onDestroy();
}
}
单例类代码:
public class SingletonSampleClass {
private Context context;
private static SingletonSampleClass instance;
private SingletonSampleClass(Context context) {
this.context = context;
}
public synchronized static SingletonSampleClass getInstance(Context context) {
if (instance == null) instance = new SingletonSampleClass(context);
return instance;
}
public void onDestroy() {
if(context != null) {
context = null;
}
}
}
怎么解决?
1.不要传递activity的context,传递applicationContext
2.假如一定要传activity的context,请在onDestroy方法中把传递进去的context置为空
4.内部类引用
看下以下例子,假如定义了一个叫做LeakyClass 的内部类,然后把当前activity传递进去:
public class InnerClassReferenceLeakActivity extends AppCompatActivity {
/*
* Mistake Number 1:
* Never create a static variable of an inner class
* Fix I:
* private LeakyClass leakyClass;
*/
priva

967

被折叠的 条评论
为什么被折叠?



