Почему BroadcastReceiver работает, даже когда приложение находится в фоновом режиме?

Я проверяю подключение к Интернету в своем приложении с помощью BroadcastReceiver, и я показываю диалог предупреждения, если соединение потеряно. Он работает нормально. Но моя проблема заключается в том, что BroadcastReceiver работает, даже если мое приложение находится в фоновом режиме. Таким образом, диалог появляется, когда интернет-соединение теряется, даже если пользователь находится в другом приложении. Это полностью разрушает мое приложение.

Кто-нибудь понял, как ограничить приемник Broadcast только в приложении?

Вот мой BroadcastReceiver:

 public class ConnectivityChangedReceiver extends BroadcastReceiver{

    @Override
    public void onReceive( Context context, Intent intent )
     {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    if (networkInfo != null && networkInfo.isConnected()) {
    } else {
        try{
            Intent i=new Intent(context, InternetDialogActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
        } catch(Exception e){
            e.printStackTrace();
        }
    }
  }
}

А активность:

 public class InternetDialogActivity extends Activity implements OnClickListener{
   @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.internet_dialog_box);
      getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
      Button retryButton = (Button) findViewById(R.id.retryInternetButton);
      retryButton.setOnClickListener(this);
    }

   public boolean checkConnectivity(){
       ConnectivityManager connectivityManager   = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
           NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

       if (networkInfo!=null && networkInfo.isConnected()) {
           finish();
           return true;
       } else {
           Intent intent = getIntent();
           finish();
           startActivity(intent);
           return false; 
      }
   }

   @Override
   public void onClick(View view) {
      switch(view.getId()){
         case R.id.retryInternetButton:
             try{
                 checkConnectivity();
             } catch(Exception e){
                 e.printStackTrace();
             }
             break;
       }
   }
   }

Вот как я объявил приемник и активность в манифесте:

  <receiver android:name="com.lisnx.service.ConnectivityChangedReceiver"
        android:label="NetworkConnection">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
        </intent-filter>
  </receiver>

  <activity android:name="com.lisnx.activity.InternetDialogActivity"
        android:configChanges="orientation|keyboardHidden"
        android:theme="@android:style/Theme.Dialog" />

Я читал, что мы можем ограничить использование BroadcastReceiver в приложении, не объявляя его в манифесте. Но я не знаю, как будет работать приемник? Пожалуйста, помогите мне. Я застрял на нем плохо. Thanx заранее.

Ответы

Ответ 1

A BroadcastReceiver работает, когда приложение находится в фоновом режиме, потому что событие, которое получает получатель, отправляется по всему миру, и каждое приложение зарегистрирован для прослушивания на них, независимо от того, работает он или нет.

Чтобы справиться с этим, в коде BroadcastReceiver onReceive проверьте, находится ли ваше приложение на переднем плане.

Существует один - и только тот, который я знаю - это эффективный метод для этого. Вам нужно следить за действиями вашей паузы/возобновления для своего приложения. Убедитесь, что вы проверяете это в каждой активности.

В этом ответе есть пример кода (решение # 1). В вашем случае вы хотели бы проверить MyApplication.isActivityVisible() == true как проверку, прежде чем что-либо делать со своего BroadcastReceiver.

Ответ 2

Вы пытались удалить фильтр Intent из манифеста и зарегистрировать/отменить его в действии? Таким образом, вы можете попытаться зарегистрировать фильтр Intent в onStart() и отменить его на методах onStop(). Код выглядит примерно так:

static final String ACTION = "android.net.conn.CONNECTIVITY_CHANGE";


IntentFilter filter = new IntentFilter(ACTION);
this.registerReceiver(ConnectivityChangedReceiver, filter);


unregisterReceiver(ConnectivityChangedReceiver);

Вы также должны узнать о жизненном цикле активности, если он еще не знаком.

Ответ 3

Вы должны зарегистрировать/отменить регистрацию BroadcastReceiver в onPause() и onResume() каждого действия. Тогда вы знаете, что приемник только "прослушивает", когда ваше приложение находится на переднем плане. Вы можете легко сделать это, создав свой собственный BaseActivity, который расширяет Activity и переопределяет onPause() и onResume() и регистрирует/отменяет регистрацию вашего ресивера. Просто выполните все ваши действия BaseActivity и попросите их позвонить в super.onResume() и super.onPause(), как обычно. Вот пример кода:

public class BaseActivity extends Activity {
    // Create an IntentFilter to listen for connectivity change events
    static IntentFilter filter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
    // Create an instance of our BroadcastReceiver
    static ConnectivityChangedReceiver receiver = new ConnectivityChangedReceiver();

    @Override
    protected void onPause() {
        super.onPause();
        // Stop listening for connectivity change events
        unregisterReceiver(receiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Listen for connectivity change events
        registerReceiver(receiver, filter);
    }
}

Все ваши действия должны расширять BaseActivity, и если им нужно сделать что-нибудь особенное в onResume() или onPause(), просто зайдите в super.onXXXXX() следующим образом:

public MyActivity extends BaseActivity {
    @Override
    protected void onResume() {
        super.onResume();
        // Here you do whatever you need to do in onResume() of your activity
        ...
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Here you do whatever you need to do in onPause() of your activity
        ...
    }
}

Я не запускал код через компилятор, поэтому прошу прощения, если там опечатка или я что-то пропустил.

Ответ 4

Я думаю, вам нужно будет убедиться, что вы не используете приемник, когда приложение находится в фоновом режиме. Для этого вам придется использовать все действия onPause() и onResume().

Ответ 5

Чтобы сделать широковещательный приемник, который запускается только при запуске приложения, следуйте приведенному ниже коду.

1. Создайте свой широковещательный приемник следующим образом:


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class InternetStatusNotifier extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        //Recieve notification here

    }

}

2. Сделайте операцию или фрагмент, где вы хотите, чтобы широковещательный приемник работал следующим образом:


import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;

public class MainActivity extends Activity {
    private InternetStatusNotifier mInternetStatusNotifier;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mInternetStatusNotifier = new InternetStatusNotifier();
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onResume() {
        registerReceiver(mInternetStatusNotifier, new IntentFilter(
                "android.net.conn.CONNECTIVITY_CHANGE"));
        super.onResume();
    }

    @Override
    protected void onPause() {
        unregisterReceiver(mInternetStatusNotifier);
        super.onPause();
    }

Примечание.. Таким образом, вы используете широковещательный приемник определенным образом. Таким образом будет отображаться только отображение на экране. Когда вы регистрируете трансляцию с использованием файла манифеста, они даже принимаются, когда приложение закрыто.

Ответ 6

Насколько я знаю, если приемник Broadcast зарегистрирован внутри manifest.xml, тогда широковещательный приемник существует до тех пор, пока приложение существует. Кроме того, динамически зарегистрированные получатели (то есть, регистрируют ваш BroadcastReceiver программно) вызываются в потоке пользовательского интерфейса. Это означает, что ваши приемники блокируют любую обработку пользовательского интерфейса, и поэтому метод onReceive() должен быть как можно быстрее.

Однако я попытаюсь обсудить информацию о Broadcast Receiver. Но сначала нужно знать некоторую информацию. Во-первых, широковещательный приемник является автономным компонентом приложения, который означает, что он будет продолжать работать, даже если другой компонент приложения не запущен. Поэтому мы отменим регистрацию вещательного приемника в onPause на активность. Кроме того, разработчик должен зарегистрировать это в реализации Activity.onResume().

Во-вторых, разработчик не должен отменить регистрацию в Activity.onSaveInstanceState(), потому что это не будет вызываться, если пользователь вернется в стек истории. Я передал эту информацию из Документация BroadcastReceiver.

Другое дело, что объект BroadcastReceiver действителен только для продолжительности вызова onReceive(). Как только метод onReceive() будет завершен, ваш BroadcastReceiver завершится.

Теперь, как программно зарегистрировать приемник:

public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)

Здесь BroadcastReceiver-приемник будет вызываться, когда любое намерение трансляции совпадает с фильтром.
      IntentFilter-Intent указывает, какое событие прослушивает ваш приемник.

Регистрация:

YourConnectionListener receiver;
this.reciever = new YourConnectionListener();
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(this.reciever, filter);

Отправил вашу информацию о вещании:

Intent intent = new Intent();
intent.putExtra("Message", "Your connectivity info has Changed!!"); 
this.sendBroadcast(intent);

Получатель:

Теперь вам нужно получить трансляцию. Android вызывает метод onReceive() для всех зарегистрированных широковещательных приемников всякий раз, когда происходит событие. Предположите, что вы хотите получать уведомления о каждом изменении соединения.

public class YourConnectionListener extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent){
         // your Code
    }
}   

onReceive() имеет два аргумента:

  • Контекст
  • : объект контекста, который вы можете использовать для доступа к дополнительной информации или для запуска служб или действий.
  • Цель: намерение, используемое для регистрации вашего ресивера. Этот объект содержит дополнительную информацию, которую вы можете использовать в своей реализации.
    Кроме того, разработчик должен избегать любых длительных задач в вашем BroadcastReceiver. Итак, в статически и динамически зарегистрированных получателях разработчик должен выполнять незначительные задачи в самом приемнике. Для выполнения каких-либо более длительных задач вы должны запустить службу из своего получателя.

Ответ 7

То, как широковещательные приемники работают в Android. Если вы зарегистрируетесь для трансляции в манифесте, и ваше приложение не запущено, Android начнет новый процесс обработки широковещательной передачи. Как правило, плохой идеей является прямой показ пользовательского интерфейса от широковещательного приемника, поскольку это может прервать другие приложения. Я также не уверен, что универсальный диалог "потерянный соединение" также является хорошей идеей. Вероятно, это должно быть связано с каждым видом деятельности, использующим сетевой доступ.

Что касается оригинального вопроса, вам нужно отключить приемник, когда ваша деятельность идет в фоновом режиме (onPause() и т.д.) и включите его, когда вы перейдете на передний план (onResume() и т.д.). Поместите enabled=false в ваш манифест, а затем используйте что-то вроде этого в своем коде, чтобы переключить его по мере необходимости:

   public static void toggle(Context context, boolean enable) {
        int flag = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
        ComponentName receiver = new ComponentName(context,
                ConnectivityMonitor.class);

        context.getPackageManager().setComponentEnabledSetting(receiver, flag,
                PackageManager.DONT_KILL_APP);
   }

Ответ 8

Простой способ определить, находится ли приложение на переднем плане или нет.

if((mContext.getPackageName().equalsIgnoreCase(
                ((ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE))
                        .getRunningTasks(1).get(0).topActivity.getPackageName())))
{
//app is in foreground;
}

Ответ 9

Я предлагаю вам проверить настройки Интернета из приложения, когда кто-то его откроет, вот фрагмент кода, как я это делаю.

public static boolean isNetworkConnected(Context ctx) {  
        ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);  
        NetworkInfo ni = cm.getActiveNetworkInfo();  
        if (ni == null) {  
            return false; // There are no active networks.  
        } else  
            return true;  
    }