【Android性能优化】9个方法避免内存泄漏

前言

我们做开发的时候,很容易专注于做功能和业务层面的开发,而忽略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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员-薯片

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值