【问题标题】:Memory leak happening. Unable to detect the leak and clean it发生内存泄漏。无法检测到泄漏并进行清洁
【发布时间】:2018-09-25 17:18:34
【问题描述】:

我有下面的 ConnectivityReceiver 类,它扩展了用于检查互联网连接的 BroadcastReceiver。 还有另一个活动 SplashActivity,它实现了这个类来检查互联网连接。我在 OnCreate 中注册接收器并在 OnDestroy 方法中取消注册它。但是,在进行下一个活动之后,LeakCanary 仍然在 SplashActivity 中显示内存泄漏。

我在 MyApplication 类中实例化了 LeakCanary 和一些方法。 请在下面找到泄漏的屏幕截图。

有人可以帮我检测内存泄漏并解决这个问题吗?

ConnectivityReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

public class ConnectivityReceiver extends BroadcastReceiver
{
    public static ConnectivityReceiverListener connectivityReceiverListener;
    public ConnectivityReceiver()
    {
        super();
    }

    @Override
    public void onReceive(Context context, Intent arg1)
    {
        if(arg1.getAction() != null && arg1.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION))
        {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            if(cm != null)
            {
                NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
                boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();

                if (connectivityReceiverListener != null)
                    connectivityReceiverListener.onNetworkConnectionChanged(isConnected);
            }
        }
    }
    public static boolean isConnected()
    {
        ConnectivityManager cm = (ConnectivityManager) MyApplication.getInstance().getApplicationContext()
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if(cm != null)
        {
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
        }
        return false;
    }
    public interface ConnectivityReceiverListener
    {
        void onNetworkConnectionChanged(boolean isConnected);
    }
}

MyApplication.java

import android.app.Application;
import com.squareup.leakcanary.LeakCanary;

public class MyApplication extends Application
{
    private static MyApplication mInstance;

    @Override
    public void onCreate()
    {
        super.onCreate();
        mInstance = this;

        if(LeakCanary.isInAnalyzerProcess(this))
            return;
        LeakCanary.install(this);
    }
    public static synchronized MyApplication getInstance()
    {
        return mInstance;
    }
    public void setConnectivityListener(ConnectivityReceiver.ConnectivityReceiverListener listener)
    {
        ConnectivityReceiver.connectivityReceiverListener = listener;
    }
}

SplashActivity.java

public class SplashActivity extends AppCompatActivity implements ConnectivityReceiver.ConnectivityReceiverListener
{
    final int REQUEST_CODE_RECOVER_PLAY_SERVICES = 1001, PERMISSION_READ_STORAGE = 0;
    RelativeLayout relativeLayout;
    IntentFilter intentFilter;
    ConnectivityReceiver connectivityReceiver;
    Bitmap thumbnail;

    @Override
    public void onCreate(Bundle icicle)
    {
        super.onCreate(icicle);
        Fabric.with(this, new Crashlytics());

        setContentView(R.layout.activity_main);

        intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        connectivityReceiver = new ConnectivityReceiver();

        registerReceiver(connectivityReceiver, intentFilter);

        if(checkInternet())
        {
             Intent mainIntent = new Intent(SplashActivity.this, WelcomeActivity.class);
             SplashActivity.this.startActivity(mainIntent);
             SplashActivity.this.finish();
        }
    }

    boolean checkInternet()
    {
        boolean isConnected = ConnectivityReceiver.isConnected();
        showSnack(isConnected);
        return isConnected;
    }
    private void showSnack(boolean isConnected)
    {
        Snackbar snackbar = Snackbar.make(relativeLayout, AppConfig.noInternet, Snackbar.LENGTH_INDEFINITE);
        if(!isConnected)
        {
            snackbar.setAction("GO OFFLINE", new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent mainIntent = new Intent(SplashActivity.this, WelcomeActivity.class);
    SplashActivity.this.startActivity(mainIntent);
    SplashActivity.this.finish();
                }
            });
            View sbView = snackbar.getView();
            TextView textView = sbView.findViewById(android.support.design.R.id.snackbar_text);
            textView.setTextColor(Color.WHITE);

            snackbar.setActionTextColor(getResources().getColor(R.color.colorPrimary));
            snackbar.show();
        }
        else
            snackbar.dismiss();
    }
    @Override
    public void onDestroy() {
        unregisterReceiver(connectivityReceiver);
        connectivityReceiver = null;
        super.onDestroy();
    }

    @Override
    public void onPause()
    {
        super.onPause();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        MyApplication.getInstance().setConnectivityListener(this);
    }

    @Override
    public void onNetworkConnectionChanged(boolean isConnected)
    {
        showSnack(isConnected);
    }
}

【问题讨论】:

  • 这是由于您使用静态侦听器来保持活动。阅读本文以获取帮助:stackoverflow.com/questions/11908039/…
  • 那是因为我将在许多活动中使用这个类对象,并避免一直实例化它。什么是更好的解决方案?
  • 正如我在您的 SplashActivity 中看到的,您做了两件事:1 是实例化 ConnectivityReceiver,2 是 MyApplication.getInstance().setConnectivityListener(this);乙>。这意味着您正在使用 ConnectivityReceiver 并在本地设置侦听器。我不知道你为什么认为它可以避免在许多活动中实例化。因为当您在另一个活动上使用它时,您必须再次执行上述两个步骤。
  • 在 SplashActivity 中实例化 ConnectivityReceiver 是为接收者 registerReceiver(connectivityReceiver, intentFilter); 注册它并使用 MyApplication.getInstance( ).setConnectivityListener(this); 用于调用监听器。你能告诉我如何改进这段代码吗?
  • 移除监听器的静态声明并通过构造函数注入监听器。并在 SplashActivity 创建接收器: connectivityReceiver = new ConnectivityReceiver(this); 。然后创建新方法以在 ConnectivityReceiver 中设置 listener = null。我假设方法名称为 removeListener()。在 SplashActivity - onStop() 调用connectivityReceiver.removeListener();切断接收器与您的活动之间的连接。它可以帮助您避免内存泄漏。忘记 MyApplication 类中的代码

标签: java android memory-leaks leakcanary


【解决方案1】:

你需要onPause()onStop();中的unregisterReceiver(connectivityReceiver);接收器,因为onDestroy();直到Activity堆栈中的Activity才会被调用。 onDestroy(); 将在您完成 Activity 时调用,unregisterReceiver(connectivityReceiver); 将被执行。

【讨论】:

  • 我会试试这个并回复你
猜你喜欢
  • 2012-07-16
  • 1970-01-01
  • 1970-01-01
  • 2021-09-01
  • 2012-01-22
  • 1970-01-01
相关资源
最近更新 更多