gpt4 book ai didi

java - BroadcastReceiver 意外调用了 onReceive()

转载 作者:行者123 更新时间:2023-12-01 14:38:06 25 4
gpt4 key购买 nike

我有一个应用程序,我想在其中每隔 15 分钟查找一些数据。我有一个以警报启动的服务,但我还想在开始查找之前确保有网络连接。

为此,我认为我应该使用 BroadcastReceiver 来监视网络状态的更改。我包装了一个广播接收器来帮助解决这个问题:

public abstract class NetworkMonitor extends BroadcastReceiver
{
boolean mDoingStuff;

public abstract void doStuff();

public NetworkMonitor()
{
mDoingStuff = false;

IntentFilter networkStateFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
MyApp.getContext().registerReceiver(this, networkStateFilter);
}

@Override
public void onReceive(Context context, Intent intent)
{
// network state changes, you can process it, information in intent
ConnectivityManager cn = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = ConnectivityManagerCompat.getNetworkInfoFromBroadcast(cn, intent);

// Only use Wifi Connections for updating this
if (info.isConnectedOrConnecting() && !mDoingStuff)
{
mDoingStuff = true;
doStuff();
}
}
}

然后我在类似的服务中使用它:

public class WidgetUpdateService extends Service
{
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// Build the async task to get the data
final MyAsyncTask mTask = new MyAsyncTask();

// Register an interest in when the network changes
new NetworkMonitor(false)
{
public void doStuff()
{
mTask.execute();
}
};

// Make sure that if we get shut down then we get started again correctly.
return START_REDELIVER_INTENT;
}


protected class MyAsyncTask extends AsyncTask<Void, Void, Void>
{
public MyAsyncTask()
{
}

@Override
protected Integer doInBackground(Void... arg0)
{
// do work
}

@Override
protected void onPostExecute(Integer result)
{
WidgetUpdateService.this.stopSelf();
}

@Override
protected void onCancelled(Integer result)
{
WidgetUpdateService.this.stopSelf();
}
}
}

其中 MyAsyncTask 是一个内部类,它将导致服务在完成时停止Self()。

这有点管用,但是:

  1. (根据 logcat)我收到的对 NetworkMonitor.doStuff() 的调用比我预期的要多得多。看来,即使服务已停止(异步任务正确完成后),NetworkMonitor 实例仍在接收有关网络状态更改的 Intent 。为什么是这样?
  2. 我是否需要一个变量来在服务中存储 NetworkMonitor() 实例,或者我可以只拥有一个像这样的匿名实例吗?查看文档,BroadcastReceiver 应该在 onReceive() 完成后自行清理。
  3. 为什么我需要NetworkMonitor.mDoingStuff?我猜如果我能弄清楚为什么 NetworkMonitoronReceive() 完成后没有自行清理,那么我可能不再需要它了?
  4. 这是一种明智的做法还是我在自找麻烦?

如果您需要更多信息,请告诉我,我很乐意提供。

最佳答案

This kinda works

这是可怕的代码,恕我直言。

It seems that even when the service has been stopped (after the async task has finished correctly) the NetworkMonitor instance is still being receiving intents about changes to the network state. Why is this?

因为你永远不会注销接收器。它会继续运行,并像筛子一样泄漏内存,直到您的进程终止。

Do I need to have a variable to store the NetworkMonitor() instance in the service, or can I just have an anonymous instance like this?

您需要有一个实例,以便稍后可以取消注册。接收者的注册和注销应由服务完成;你的 register-the-receiver-in-its-constructor 是使你的代码变得可怕的部分原因。

Looking at the docs the BroadcastReceiver should clear itself up after onReceive() has finished

list 注册的 BroadcastReceiver 为单个广播而存在。通过 registerReceiver() 注册的 BroadcastReceiver 会一直存在,直到 unregisterReceiver()

Why do I need NetworkMonitor.mDoingStuff?

你有更大的问题。

Is this a sensible way of doing this

不完全是。

首先,您将在第二次广播时崩溃,因为您无法多次 execute() AsyncTask 实例。

其次,请参阅前面提到的无法取消注册的问题。

第三,如果您想要一个服务只做一件事,然后就消失,请使用 IntentService

那么,让我们一路回到顶部:

I have an app in which I want to perform lookup some data every, say, 15 mins. I have a service that I start with an alarm, but I also want to make sure that there is a network connection before I start looking.

正确的做法是:

  • 将您的 AlarmManager 事件路由到 BroadcastReceiver。如果您使用 _WAKEUP 警报类型,这一点尤其重要,因为只有使用 BroadcastReceiver PendingIntent 时,此类事件才可靠。

  • BroadcastReceiver 中,在 onReceive() 中,如果您有网络连接,请向 IntentService 发送命令以完成这项工作(并且,如果您使用 _WAKEUP 闹钟类型,请考虑我的 WakefulIntentService,以便设备在您执行此操作时保持唤醒状态)。

  • 如果似乎没有网络连接,请让您的 BroadcastReceiver 启用另一个 list 注册的 BroadcastReceiver 设置来监视 CONNECTIVITY_ACTION 事件 - 为此使用 PackageManagersetComponentEnabledSetting()

  • CONNECTIVITY_ACTION BroadcastReceiver中,在onReceive()中,如果您确定现在有网络连接,请启动您的 IntentService(如果您已建立连接,则与您在 AlarmManager 接收器中执行的操作相同)。

  • IntentService/WakefulIntentService中,在onHandleIntent()中完成您的工作。它已经有一个后台线程,并且当没有更多工作要做时就会调用 stopSelf()

  • IntentService/WakefulIntentServiceonDestroy() 中,禁用 CONNECTIVITY_ACTION BroadcastReceiver 通过 PackageManagersetComponentEnabledSetting(),将您返回到原始状态。

这样:

  1. 您不会泄漏内存,就像您在这里所做的那样。

  2. 您不必像在这里那样弄乱线程代码。

  3. 您不必担心在警报和获得连接之间您的进程是否会被踢出内存。

  4. 如果连接被阻止一段时间(例如,飞行模式),您无需像此处那样注册 N 个接收器并设置 N 个 AsyncTasks。相反,当闹钟响起后,只要将来连接发生变化,您就可以再次获得控制权。

关于java - BroadcastReceiver 意外调用了 onReceive(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16288901/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com