ConnectivityManager泄漏,不确定如何解决。

17

所以,我有一个方法可以告诉我用户是否有活动的互联网连接。它运行良好。但是,LeakCanary已经识别出与connectivityManager相关的内存泄漏。目前,我在我的代码中没有任何时候关闭connectivityManager。

我尝试在onDestroy中关闭connectivityManager。但要么这不是一个选项,要么我不知道该怎么做。说实话,我只是尝试让自动填充告诉我如何做。但没有成功。

public static boolean isNetworkAvailable(Context context) {
    ConnectivityManager connectivityManager =(ConnectivityManager)  context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo =connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo !=null && activeNetworkInfo.isConnected();
}

context.getSystemService 可以被 getSystemService 替换。 - santosh kumar
@santosh,我在进行更改后遇到了以下错误。无法从静态上下文引用非静态方法“getSystemService(java.lang.string)”。 - seekingStillness
那么你的代码就是好的。 - santosh kumar
1
请使用应用程序上下文而不是活动上下文来防止泄漏。请参考答案。 - santosh kumar
5个回答

35

使用此功能可防止泄露。

ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext()
                .getSystemService(Context.CONNECTIVITY_SERVICE);

谢谢,我已经添加了代码,没有错误。测试成功后,我会接受答案。 - seekingStillness
我很想了解为什么它能够防止内存泄漏/以前为什么会有内存泄漏。 - yotam hadas
3
@yotamhadas 这是因为在代码中你可能持有上下文的死引用并尝试注册ConnectivityManager。在应用程序上下文中可以保存我们,因为它不会死亡直到应用程序被杀死。最好的做法是将ConnectivityManage和wifiManager放在应用程序级别而不是活动级别。 - santosh kumar

8
这是Android M上的一个bug,在L版本已经修复。
原因是在M版本中,ConnectivityManager将第一个实例作为静态对象保存。
当你使用Activity Context首次获取时,静态对象将始终引用您的Activity。改为使用Application Context即可解决该问题。

7

分享一个新答案,但有一个问题:

我尝试通过在我的活动中使用以下代码实例化ConnectivityManager来修复错误:

ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext()
            .getSystemService(Context.CONNECTIVITY_SERVICE);

然而,这并没有解决内存泄漏的问题。问题在于,在我的活动被调用之前,某些依赖库可能在其代码中内部使用了 ConnectivityManager,从而导致上下文的静态变量被初始化为活动上下文。解决这个问题的技巧是在应用程序类中实例化 ConnectivityManager,仅仅是为了这个目的(未使用)。
public class MyApp extends Application {
    @Override
    public void onCreate() {
         ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
    }
}

没对我起作用。 - Sébastien

1

正如@Adi所提到的,这可能是一个内部使用ConnectivityManager的库,我正在使用AdMob SDK,该SDK在初始化时使用活动上下文,正如他们在文档中提到的。 因此,为了解决这个问题,应该使用应用程序上下文而不是活动上下文。如果您正在使用AdMob SDK,请按照以下方式进行初始化。

MobileAds.initialize(this.applicationContext)

0

以上的答案都对我没用,我尝试了所有的方法。

事实证明,问题的原因是AdMob的横幅广告初始化MobileAds.initialize(requireContext()),我在其中一个片段中使用了这个方法。

解决方法是使用MobileAds.initialize(MyApplication.myAppContext)

片段中的AdMob初始化示例:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // MobileAds.initialize(requireContext()) <---- Causes Memory Leak

    MobileAds.initialize(MyApplication.myAppContext) // <---- No Memory Leak
}

我的应用示例:

class MyApplication : Application() {

    companion object {
        lateinit  var myAppContext: Context
    }

    override fun onCreate() {
        super.onCreate()

        myAppContext = applicationContext
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接