AlarmManager 和 BroadcastReceiver 而不是 Service - 这很糟糕吗? (暂停)

发布于 2024-09-06 20:17:41 字数 3747 浏览 9 评论 0原文

背景信息:

我需要从网络更新一些数据,大约每小时左右更新一次,即使我的应用程序已关闭。数据本身的更新大约需要40秒到1分钟。然后将其保存为可序列化文件。当我的应用程序启动时会读取此文件。

这是我目前采取的方法(不使用服务)

像这样使用 AlarmManager 和 BroadcastReceiver :

private void set_REFRESH_DATA_Alarm(){
    mContext = Main.this;
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    broadcast_intent = new Intent(mContext, 
            RepeatingAlarmReceiver_REFRESH_DATA.class);
    pendingIntent = PendingIntent.getBroadcast(mContext, 0,  broadcast_intent, 0);
    // do a REFRESH every hour, starting for the first time in 30 minutes from now ...
    Calendar now = Calendar.getInstance();
    long triggerAtTime = now.getTimeInMillis()+ (1 * 30 * 60 * 1000); // starts in 30 minutes
    long repeat_alarm_every = (1 * 60 * 60 * 1000); // repeat every 60 minutes
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, 
            repeat_alarm_every, pendingIntent);
}

我的 RepeatingAlarmReceiver_REFRESH_DATA.class 负责更新来自 Web 的数据:

public class RepeatingAlarmReceiver_REFRESH_DATA extends BroadcastReceiver {

    public static Context mContext;
    ConnectivityManager mConnectivity;

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext = context;
        // if Network connection is OK (Wifi or Mobile) then Load data ...
        mConnectivity = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        Log.i("Hub",
                "mConnectivity.getNetworkInfo(0)="
                        + mConnectivity.getNetworkInfo(0));
        Log.i("Hub",
                "mConnectivity.getNetworkInfo(1)="
                        + mConnectivity.getNetworkInfo(1));
        if ((mConnectivity.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED)
                || (mConnectivity.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED)) {
            Log.i("Hub", "Connectivity OK ...");
            Refresh_HIST_DATA();
        } else {
            // else Show Dialog "No network connection" ...
            Log.i("Hub",
                    "No network connection for the moment... will try again later!");
        }
    }

    // =========================================================================
    private void Refresh_HIST_DATA() {
        Log.i("Hub", "Refresh_HIST_DATA()... Starting ...");
        // etc...
    }
}

在清单中我有:

<receiver android:name="com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA" android:process=":remote" />

问题:

警报按时触发并开始更新,但大约 10 秒后停止(超时):

06-25 11:55:05.278: 警告/ActivityManager(76):超时 广播广播记录{44bb4348 无效的} - 接收者=android.os.BinderProxy@44bcc670

06-25 11:55:05.278: 警告/ActivityManager(76):接收器 超时期间:ResolveInfo{44bb42c0 com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA p=0 o=0 m=0x0}

06-25 11:55:05.278:信息/过程(76): 发送信号。 PID:819 SIG:9

06-25 11:55:05.298: 信息/ActivityManager(76):流程 com.cousinHub.myapp:远程(pid 819) 已经死了。

ps:奇怪的是,在我的 HTC Hero(仍在 Android 1.5 - API Level 4)上大约 10 秒后,这个“超时”并没有发生,但在我的 Nexus One(2.1-update1)上却很好

问题:

  1. 为什么会超时?有什么简单的方法可以避免这种情况吗?
  2. 我是否在清单中正确设置了 BroadcastReceiver?我需要添加一些东西(以避免超时)吗?
  3. 我绝对应该选择这种“从网络刷新”功能的服务吗? (考虑这篇文章:http://www .androidguys.com/2009/09/09/diamonds-are-forever-services-are-not/) 如果是(我应该切换到服务):任何好的代码/教程片段......

一如既往,感谢您的帮助。

H.

BACKGROUND INFO:

I need to update some data from the web, about every hour or so, even when my app is closed. The update of the data itself takes about 40 seconds to 1 minute. It is then saved as a Serializable to a file. This file is read when my app starts.

THIS IS THE APPROACH I TOOK FOR THE MOMENT (not using a Service)

use the AlarmManager and BroadcastReceiver like this :

private void set_REFRESH_DATA_Alarm(){
    mContext = Main.this;
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    broadcast_intent = new Intent(mContext, 
            RepeatingAlarmReceiver_REFRESH_DATA.class);
    pendingIntent = PendingIntent.getBroadcast(mContext, 0,  broadcast_intent, 0);
    // do a REFRESH every hour, starting for the first time in 30 minutes from now ...
    Calendar now = Calendar.getInstance();
    long triggerAtTime = now.getTimeInMillis()+ (1 * 30 * 60 * 1000); // starts in 30 minutes
    long repeat_alarm_every = (1 * 60 * 60 * 1000); // repeat every 60 minutes
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, 
            repeat_alarm_every, pendingIntent);
}

My RepeatingAlarmReceiver_REFRESH_DATA.class takes care of updating the Data from the Web:

public class RepeatingAlarmReceiver_REFRESH_DATA extends BroadcastReceiver {

    public static Context mContext;
    ConnectivityManager mConnectivity;

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext = context;
        // if Network connection is OK (Wifi or Mobile) then Load data ...
        mConnectivity = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        Log.i("Hub",
                "mConnectivity.getNetworkInfo(0)="
                        + mConnectivity.getNetworkInfo(0));
        Log.i("Hub",
                "mConnectivity.getNetworkInfo(1)="
                        + mConnectivity.getNetworkInfo(1));
        if ((mConnectivity.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED)
                || (mConnectivity.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED)) {
            Log.i("Hub", "Connectivity OK ...");
            Refresh_HIST_DATA();
        } else {
            // else Show Dialog "No network connection" ...
            Log.i("Hub",
                    "No network connection for the moment... will try again later!");
        }
    }

    // =========================================================================
    private void Refresh_HIST_DATA() {
        Log.i("Hub", "Refresh_HIST_DATA()... Starting ...");
        // etc...
    }
}

In the Manifest I have :

<receiver android:name="com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA" android:process=":remote" />

PROBLEM :

The alarm gets fired on time and the update starts but then after about 10 seconds it stops (Timeout):

06-25 11:55:05.278:
WARN/ActivityManager(76): Timeout of
broadcast BroadcastRecord{44bb4348
null} -
receiver=android.os.BinderProxy@44bcc670

06-25 11:55:05.278:
WARN/ActivityManager(76): Receiver
during timeout: ResolveInfo{44bb42c0
com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA
p=0 o=0 m=0x0}

06-25 11:55:05.278: INFO/Process(76):
Sending signal. PID: 819 SIG: 9

06-25 11:55:05.298:
INFO/ActivityManager(76): Process
com.cousinHub.myapp:remote (pid 819)
has died.

ps: strangely enough, this "Timeout" does not happen after about 10 seconds on my HTC Hero (still on Android 1.5 - API Level 4) but well on my Nexus One (2.1-update1)

Questions :

  1. Why this timeout ? Any easy way to avoid this ?
  2. Did I set up my BroadcastReceiver correctly in the manifest ? Do I need to add something (to avoid this timeout) ?
  3. Should I absolutely go for a Service for this kind of "Refresh from Web" functionality ? (considering this article : http://www.androidguys.com/2009/09/09/diamonds-are-forever-services-are-not/)
    If YES (I should switch to a service): Any good snippets of code/tutorial for this ...

As allways, thanks for your help.

H.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

メ斷腸人バ 2024-09-13 20:17:41

为什么会超时?

您正在主应用程序线程上运行。您不能在主应用程序线程上运行超过几秒钟。另外,在执行此操作时,您会损害设备的性能(因为您以前台优先级运行),例如导致游戏或视频帧率丢失。

有什么简单的方法可以避免这种情况吗?

不要在主应用程序线程上执行大量工作(>100 毫秒)。将您的 BroadcastReceiver 委托给 IntentService,可能是 <代码>WakefulIntentService

我设置了广播接收器吗
清单中是否正确?

拜托拜托拜托拜托请摆脱android:process=:remote。您不需要它,它对您没有帮助,而且还会进一步降低设备的性能。

我绝对应该寻求服务吗
对于这种“从网络刷新”
功能? (考虑到这一点
文章 :
http://www.androidguys.com/ 2009/09/09/钻石-永远-服务-不是/)
如果是(我应该切换到服务):
任何好的代码/教程片段
这...

恕我直言,是的。然后,我又写了那篇博客文章。有关示例,请参阅 WakefulIntentService 项目。

Why this timeout ?

You are running on the main application thread. You cannot run on the main application thread for more than a few seconds. Also, while doing this, you are harming the performance of the device (because you are running with foreground priority), such as causing frame-rate loss in games or videos.

Any easy way to avoid this ?

Don't do significant work (>100ms) on the main application thread. Have your BroadcastReceiver delegate to an IntentService, perhaps a WakefulIntentService.

Did I set up my BroadcastReceiver
correctly in the manifest ?

Please please please please please get rid of the android:process=:remote. You do not need it, it is not helping you, and it is degrading performance of the device even further.

Should I absolutely go for a Service
for this kind of "Refresh from Web"
functionality ? (considering this
article :
http://www.androidguys.com/2009/09/09/diamonds-are-forever-services-are-not/)
If YES (I should switch to a service):
Any good snippets of code/tutorial for
this ...

IMHO, yes. Then again, I wrote that blog post. For an example, see the WakefulIntentService project.

孤蝉 2024-09-13 20:17:41

作为信息,我尝试使用一个新线程,它在 Wifi 上可以工作(当手机处于睡眠状态时,需要大约 1'30" 来更新数据,它不会被“杀死”!

//let's try with a new separate thread ?
        new Thread(new Runnable() {
            public void run() {
                Refresh_HIST_DATA();
            }
          }).start();

但在移动 (GPRS) 上时则不行,因为它在大约 10 秒后被杀死!

目前这只是半个解决方案,我将尝试 CommonsWare 的解决方案以获得更清洁/更可持续的方法...

让我们看看新的线程解决方案是否始终正常工作或只是运气好(我只测试了几个小时)...

如果其他人有其他建议,请发布。

For information, I've tried with a new thread and it works when on Wifi (takes about 1'30" to update the data when phone is asleep, it doesn't get 'killed' !

//let's try with a new separate thread ?
        new Thread(new Runnable() {
            public void run() {
                Refresh_HIST_DATA();
            }
          }).start();

but NOT when on Mobile (GPRS), as it gets killed after about 10 secs!

It's half-a-solution for the moment and I will try CommonsWare's solution for a cleaner/more sustainable approach...

Let's see if the new thread solution works allways fine or was just luck (I've tested only during a couple hours) ...

If anyone else has another suggestion, please do post it.

淡紫姑娘! 2024-09-13 20:17:41

而不是线程。您可以从广播接收器的 onRecive() 方法启动 AsyncTask。这不会阻塞 UI 线程。我自己在我的项目中也做了同样的事情,性质相同,即它必须每 1 小时发布一次数据。

public void onReceive(Context context, Intent intent) {
        // start your Asynctask from here. which will post data in doInBackground() method
}

Instead of thread. You can start a AsyncTask from your broadcast receiver onRecive() method. This will not block the UI thread. I myself have done same in my projects which is of same nature i.e. It has to post data every 1 hour.

public void onReceive(Context context, Intent intent) {
        // start your Asynctask from here. which will post data in doInBackground() method
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文