Проблемы с 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()?

Но я предполагаю, что я должен отменить регистрацию Receiver, а затем зарегистрировать его снова, чтобы быть готовым к следующему событию подключения, верно? Если текущий unregisterReceiver не относится к намерению или инициированному событию, то как правильно написать инструкцию и связать ее?

Я проверил в отладчике, что Intent срабатывает, и BroadcastReceiver получает событие, но я просто не знаю, как преодолеть эту просочившуюся ошибку. Любые идеи? Я упускаю что-то важное? Вы видите ошибку? Спасибо за ваш интерес.


person Carlos Botero    schedule 30.10.2017    source источник


Ответы (3)


Отмените регистрацию вашего получателя objGloInternetConnectorReceiver в обратном вызове OnDestroy() вашего LMMoviesMainActivity

 @Override
     protected void onDestroy() {
            super.onDestroy();

          unregisterReceiver(objGloInternetConnectorReceiver);

        }
person Avinash Roy    schedule 30.10.2017
comment
Спасибо за быстрый ответ. Вопрос: нужно ли мне снова выполнять: registerReceiver? (на следующее событие изменения интернет-соединения). Если да, то где мне нужно разместить команду registerReceiver? - person Carlos Botero; 30.10.2017
comment
зарегистрируйте приемник при создании и отмените регистрацию в onDestroy, вот и все - person Avinash Roy; 30.10.2017
comment
или вы можете сделать так, как предложил @Anonymous, или мой способ, оба работают нормально - person Avinash Roy; 30.10.2017

Вы должны регистрироваться для широковещательного приемника только один раз, а не регистрироваться каждый раз. Каждый раз, когда вы регистрируетесь для широковещательного приемника, вы должны отменить его регистрацию. Регистрация каждый раз внутри метода вызывает утечку. Удалите его и зарегистрируйтесь только в onResume и отмените регистрацию в при паузе.

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(objGloInternetConnectorReceiver, internetConnectionGloIntentFilter);
}

@Override
protected void onPause() {
    unregisterReceiver(objGloInternetConnectorReceiver);
    super.onPause();
}
person Sharath kumar    schedule 30.10.2017

У вас есть несколько проблем в вашем коде. Вам не нужно проверять, отображается ли действие, если вы регистрируете приемник в 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();
            }
        }
    }
}
person Mark Sitro    schedule 30.10.2017
comment
Спасибо мистеру Марку Ситро. Я реализовал ваше решение, и оно работает! Это заставило меня задаться вопросом, почему InternetConnector_Receiver, реализованный как внешний класс, не работает: он запускает Intent при наличии или отключении от Интернета, но всегда генерирует ошибку leaked IntentReceiver. Возможно, я нарушаю какое-то правило в объектно-ориентированном программировании или в самой Java/Android. - person Carlos Botero; 05.11.2017