为什么广播接收器的工作原理,即使应用程序在后台?(Why BroadcastReceiver wor

2019-06-27 20:04发布

我使用的广播接收器在我的应用程序检查互联网连接,我表现出警告对话框,如果连接丢失。 它工作正常。 但我的问题是,广播接收器的工作原理,即使我的应用程序是在backgroung。 因此,对话框弹出时的网络连接丢失,即使用户是在一些其他的应用程序。 这是完全毁了我的应用程序。

有没有人有任何想法如何限制在仅应用广播接收器?

这里是我的广播接收器:

 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" />

我已阅读,我们可以限制广播接收器通过在清单中没有宣布其应用程序内工作。 但我不知道怎么会接收器的工作呢? 请帮我。 我被困在很糟糕。 Thanx提前。

Answer 1:

一个BroadcastReceiver的工作原理当应用程序在后台,因为该接收器接收到的事件在全球范围内发送,每个应用程序被注册窃听到这些,无论它是否正在运行的。

为了解决这个问题,在您的BroadcastReceiveronReceive代码,请检查您的应用程序是在前台。

有一个 - 且只有一个,我知道 - 持续有效的方法来做到这一点。 你需要保持你的暂停的跟踪/恢复您的应用程序的行为。 确保你在每一个活动检查。

有一些示例代码在这个答案 (溶液#1)。 在你的情况,你会要检查MyApplication.isActivityVisible() == true从你做任何事情之前作为验证BroadcastReceiver



Answer 2:

你试图从清单中删除的意图过滤和注册/注销它的活动? 所以,你可以尝试在onStart(注册意图过滤器),并注销它的onStop()方法。 该代码都somethink这样的:

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


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


unregisterReceiver(ConnectivityChangedReceiver);

你也应该了解活动的生命周期 ,如果是不熟悉呢。



Answer 3:

您应注册/注销你的BroadcastReceiveronPause()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
        ...
    }
}

所以我很抱歉,如果有一个错字或我错过了什么我没有通过编译运行的代码。



Answer 4:

我认为你必须确保你不使用接收器时,应用程序是在后台。 对于您将不得不使用每一个活动的onPause()和的onResume()方法。



Answer 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();
    }

注意:那你是怎么在屏幕特定的方式使用广播接收器。 只有屏幕显示会以这种方式接收广播。 当您使用清单文件,那么他们甚至收到登记广播时,应用程序被关闭



Answer 6:

据我所知,如果广播接收装置,注册内的manifest.xml然后广播接收器只要应用程序中存在的存在。 此外,动态注册的接收器(这意味着,注册您的广播接收器编程)被称为UI线程上。 这意味着你的接收机块的任何UI处理和因此onReceive()方法应该尽可能地快。

不过,我会尽量讨论有关广播接收机信息。 但是,首先应该知道的一些信息。 首先,广播接收器是一个独立的应用程序组件,这意味着它会继续运行即使当其它应用程序组件没有运行。 这就是为什么我们的onPause上的活动注销广播接收器。 此外,开发人员应在注册此Activity.onResume()的实现。

其次,开发者不应该在注销Activity.onSaveInstanceState()因为如果用户移回在历史堆栈,这将不会被调用。 我已经把从该信息广播接收器的文档 。

另一点是,一个BroadcastReceiver对象是仅适用于所述呼叫的持续时间,以的onReceive()。 只要的onReceive()方法完成后,你的广播接收器终止。

现在,如何通过编程注册您的接收器:

public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)

在这里,BroadcastReceiver-接收器会打电话的时候,任何带过滤器的广播意图匹配。
而IntentFilter-意图指定哪些事件接收机应该听。

寄存器:

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);

接收器:

现在,需要接收广播。 机器人调用每当事件发生时所有已注册的广播接收机的的onReceive()方法。 假设你想只要连接改为通知。

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

onReceive()有两个参数:

  • 背景:您可以使用上下文对象来获取更多的信息,或启动服务或活动。
  • 意图:意图用于注册接收器。 该对象包含您可以在实现中使用的附加信息。
    此外,开发人员应避免在广播接收器的任何持久的任务。 所以,在静态和动态注册的接收器,开发者应该在itself.For下去的任务,你应该从你的接收机内启动一个服务接收方做轻微的任务。


Answer 7:

这是单向广播接收器在Android中运行。 如果您注册在清单广播和您的应用程序没有运行,Android将开始一个新的进程来处理广播。 它通常是一个坏主意,直接显示从广播接收器的UI,因为这可能会中断其他应用程序。 我也不相信一个普遍的“失去连接”对话框是一个好主意,无论是。 这种情况可能由使用网络访问的每个活动进行处理。

至于原来的问题,你需要你的时候去的活动在后台(禁用接收机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);
   }


Answer 8:

找到一个简单的方法是否应用程序是在前台或不

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


Answer 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;  
    }


文章来源: Why BroadcastReceiver works even when app is in background ?