Проблемы с BroadcastReceiver для обнаружения подключения или отключения к Интернету
Цель состоит в том, чтобы реализовать BroadcastReceiver в моем приложении для Android, которое динамически определяет, когда устройство меняет свой статус подключения или отключения к Интернету. Я пробовал с несколькими учебниками и предложениями решений, но мне все еще не удается заставить его работать правильно, и я всегда получаю одну и ту же ошибку: " leaked IntentReceiver ".
Соответствующий код: во-первых, я пишу класс, производный от класса BroadcastReceiver:
public class InternetConnector_Receiver extends BroadcastReceiver {
public InternetConnector_Receiver() {}
@Override
public void onReceive(Context context, Intent intent) {
try {
boolean isVisible = MyApplication.isActivityVisible();// Check if activity is visible or not
Log.i("Activity is Visible ", "Is activity visible : " + isVisible);
// If it is visible then trigger the task else do nothing
if (isVisible == true) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
// Check internet connection and accrding to state change then text of activity by calling method
if (networkInfo != null && networkInfo.isConnected()) {
new LMMoviesMainActivity().TTSstatusDataNetChanged(true);
} else {
new LMMoviesMainActivity().TTSstatusDataNetChanged(false);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Затем я создаю связанные переменные в LMMoviesMainActivity.
Вопрос: Правильно ли активированы 3 действия, добавленные в IntentFilter, для обнаружения подключения к Интернету? Если они неверны, каковы правильные значения?
private IntentFilter internetConnectionGloIntentFilter;
private InternetConnector_Receiver objGloInternetConnectorReceiver;
internetConnectionGloIntentFilter = new IntentFilter();
internetConnectionGloIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
internetConnectionGloIntentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
internetConnectionGloIntentFilter.addAction("android.net.wifi.STATE_CHANGE");
objGloInternetConnectorReceiver = new InternetConnector_Receiver();
registerReceiver(objGloInternetConnectorReceiver, internetConnectionGloIntentFilter);
Наконец, функция, которая содержит инструкции для выполнения при изменении подключения к Интернету:
public void TTSstatusDataNetChanged(boolean isConnectedBool) {
unregisterReceiver(objGloInternetConnectorReceiver);
registerReceiver(objGloInternetConnectorReceiver, internetConnectionGloIntentFilter);
// Change status according to boolean value
if (isConnectedBool) {
if (ttsSettingsGloDialog.isShowing()) {
ttsWarningsGloTextView.setText( "Net ON" );
}
dataNetConnectedGloBool = true;
} else {
if (ttsSettingsGloDialog.isShowing()) {
ttsWarningsGloTextView.setText( "Net Off" );
}
dataNetConnectedGloBool = false;
}
}
Пытаясь выполнить: unregisterReceiver, я получаю сообщение:
Сервис com.google.android.youtube.api.service.YouTubeService утек IntentReceiver wuq@3967361, который был первоначально зарегистрирован здесь. Вы пропускаете вызов unregisterReceiver()?
Но я думаю, что я должен отменить регистрацию приемника, а затем зарегистрировать его снова, чтобы быть готовым к следующему событию подключения, верно? Если текущий unregisterReceiver не ссылается на намерение или вызванное событие, то как правильно написать инструкцию и связать ее?
Я проверил в отладчике, что Intent срабатывает, и BroadcastReceiver получает событие, но я просто не знаю, как преодолеть эту утечку. Есть идеи? Я что-то упустил? Вы видите какую-либо ошибку? Спасибо за ваш интерес.
3 ответа
У вас есть несколько проблем в вашем коде. Вам не нужно проверять, видна ли активность, если вы регистрируете получателя в onResume()
и отмените регистрацию в onPause()
,
if (networkInfo != null && networkInfo.isConnected()) {
new LMMoviesMainActivity().TTSstatusDataNetChanged(true);
} else {
new LMMoviesMainActivity().TTSstatusDataNetChanged(false);
}
Это не сработает, потому что вам нужно сослаться на фактическую активность, а не на новую. Если вы поместите BroadcastReceiver в LMMoviesMainActivity, просто сделайте
if (networkInfo != null && networkInfo.isConnected()) {
LMMoviesMainActivity.this.TTSstatusDataNetChanged(true);
} else {
LMMoviesMainActivity.this.TTSstatusDataNetChanged(false);
}
Также вам не нужно отменять регистрацию и регистрировать новый Broadcastreceiver при получении трансляции. Поэтому удалите эти строки:
unregisterReceiver(objGloInternetConnectorReceiver);
registerReceiver(objGloInternetConnectorReceiver, internetConnectionGloIntentFilter);
Вот полный пример, который должен работать: (Не забудьте инициализировать ttsSettingsGloDialog, ttsWarningsGloTextView и dataNetConnectedGloBool)
package com.test;
import android.app.Activity;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.widget.TextView;
public class LMMoviesMainActivity extends Activity {
private IntentFilter internetConnectionGloIntentFilter;
private InternetConnector_Receiver objGloInternetConnectorReceiver;
private Dialog ttsSettingsGloDialog;
private TextView ttsWarningsGloTextView;
private boolean dataNetConnectedGloBool;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
internetConnectionGloIntentFilter = new IntentFilter();
internetConnectionGloIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
internetConnectionGloIntentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
internetConnectionGloIntentFilter.addAction("android.net.wifi.STATE_CHANGE");
objGloInternetConnectorReceiver = new InternetConnector_Receiver();
}
@Override
protected void onResume() {
super.onResume();
registerReceiver(objGloInternetConnectorReceiver, internetConnectionGloIntentFilter);
}
@Override
protected void onPause() {
unregisterReceiver(objGloInternetConnectorReceiver);
super.onPause();
}
public void TTSstatusDataNetChanged(boolean isConnectedBool) {
// Change status according to boolean value
if (isConnectedBool) {
if (ttsSettingsGloDialog.isShowing()) {
ttsWarningsGloTextView.setText( "Net ON" );
}
dataNetConnectedGloBool = true;
} else {
if (ttsSettingsGloDialog.isShowing()) {
ttsWarningsGloTextView.setText( "Net Off" );
}
dataNetConnectedGloBool = false;
}
}
public class InternetConnector_Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
// Check internet connection and accrding to state change then text of activity by calling method
if (networkInfo != null && networkInfo.isConnected()) {
LMMoviesMainActivity.this.TTSstatusDataNetChanged(true);
} else {
LMMoviesMainActivity.this.TTSstatusDataNetChanged(false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Отменить регистрацию вашего приемника objGloInternetConnectorReceiver
в OnDestroy()
обратный вызов вашего LMMoviesMainActivity
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(objGloInternetConnectorReceiver);
}
Вы должны зарегистрироваться для широковещательного приема только один раз вместо регистрации каждый раз. Каждый раз, когда вы регистрируетесь для широковещательного приема, вы должны отменить его регистрацию. Регистрация каждый раз внутри метода вызывает утечку. Удалите его и зарегистрируйте только в onResume и отмените регистрацию в OnPause.
@Override
protected void onResume() {
super.onResume();
registerReceiver(objGloInternetConnectorReceiver, internetConnectionGloIntentFilter);
}
@Override
protected void onPause() {
unregisterReceiver(objGloInternetConnectorReceiver);
super.onPause();
}