Android 为什么BroadcastReceiver在应用程序处于后台时仍能工作?
我正在使用BroadcastReceiver检查应用程序中的互联网连接,如果连接丢失,我会显示一个警报对话框。它很好用。但我的问题是,即使我的应用程序在后台,广播接收器也能工作。所以,即使用户在其他应用程序中,当互联网连接断开时,对话框也会弹出。这完全毁了我的应用程序 有人知道如何仅在应用程序中限制广播接收器吗 这是我的收音机:Android 为什么BroadcastReceiver在应用程序处于后台时仍能工作?,android,broadcastreceiver,manifest,Android,Broadcastreceiver,Manifest,我正在使用BroadcastReceiver检查应用程序中的互联网连接,如果连接丢失,我会显示一个警报对话框。它很好用。但我的问题是,即使我的应用程序在后台,广播接收器也能工作。所以,即使用户在其他应用程序中,当互联网连接断开时,对话框也会弹出。这完全毁了我的应用程序 有人知道如何仅在应用程序中限制广播接收器吗 这是我的收音机: public class ConnectivityChangedReceiver extends BroadcastReceiver{ @Override
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提前。A在应用程序处于后台时工作,因为接收器拾取的事件是全局发送的,并且每个应用程序都注册以侦听这些事件,而不管它是否正在运行
要解决此问题,请在您的BroadcastReceiver
的onReceive
代码中,检查您的应用程序是否位于前台
有一种——也是我所知道的唯一一种——持续有效的方法来做到这一点。您需要跟踪应用程序的暂停/恢复操作。确保您在每个活动中都检查此项
有一些示例代码(解决方案#1)。在您的情况下,您需要先检查
MyApplication.isActivityVisible()==true
作为验证,然后再从您的BroadcastReceiver
执行任何操作,这就是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);
}
您是否已尝试从清单中删除意图筛选器并在活动中注册/取消注册它?因此,您可以尝试在onStart()中注册意图过滤器,并在onStop()方法中注销它。代码是这样的:
static final String ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
IntentFilter filter = new IntentFilter(ACTION);
this.registerReceiver(ConnectivityChangedReceiver, filter);
unregisterReceiver(ConnectivityChangedReceiver);
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
...
}
}
如果还不熟悉,您还应该了解。据我所知,如果广播接收器在manifest.xml中注册,那么只要应用程序存在,广播接收器就存在。此外,在UI线程上调用动态注册的接收器(即以编程方式注册您的BroadcastReceiver)。这意味着您的接收器会阻止任何UI处理,因此
onReceive()
方法应该尽可能快
不过,我将尝试讨论有关广播接收器的信息。但是,首先应该知道一些信息。首先,广播接收器是一个独立的应用程序组件,这意味着它将继续运行,即使其他应用程序组件没有运行。这就是为什么我们在活动暂停时注销广播接收器的原因。此外,开发人员应该在Activity.onResume()
implementation中注册此项
其次,开发人员不应在Activity.onSaveInstanceState()
中注销,因为如果用户在历史堆栈中向后移动,则不会调用此函数。我已经把那个信息从我的电脑里放了出来
另一点是,BroadcastReceiver对象仅在调用onReceive()期间有效。一旦onReceive()方法完成,您的BroadcastReceiver就会终止
现在,如何以编程方式注册接收器:
public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)
此处,当任何广播意图与筛选器匹配时,将调用BroadcastReceiver-receiver。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()
有两个参数:
- 上下文:可用于访问其他信息或启动服务或活动的上下文对象
- 意图:用于注册接收者的意图。此对象包含可在实现中使用的其他信息。
此外,开发人员应避免在您的接收器中执行任何长期任务。所以,在静态和动态注册的接收器中,开发人员应该在接收器本身中执行次要任务。对于任何更长的任务,您应该从接收器中启动服务李>
onPause()
和onResume()
中注册/取消注册您的BroadcastReceiver
。然后你就知道,当你的应用程序在前台时,接收者只是在“听”。您可以通过创建自己的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()
中执行任何特殊操作,请确保通过
if((mContext.getPackageName().equalsIgnoreCase(
((ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE))
.getRunningTasks(1).get(0).topActivity.getPackageName())))
{
//app is in foreground;
}
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
}
}
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();
}
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;
}