AlarmManager、BroadcastReceiver 和 Service 不工作

发布于 2024-12-29 14:47:49 字数 3803 浏览 2 评论 0原文

我正在重构一些代码,以便我的应用程序每天在给定时间从网站提取数据一次。根据我的研究,AlarmManager 似乎是最合适的方法。

我一直在关注的教程是: http://mobile.tutsplus.com /tutorials/android/android-fundamentals-downloading-data-with-services/

到目前为止,AlarmManagerBroadcastReceiver 似乎正在工作,但是Service 似乎永远不会启动(即 onStartCommand 似乎没有被调用)

以下是我到目前为止的代码的重要片段:

MyActivity.java

private void setRecurringAlarm(Context context) {
    Calendar updateTime = Calendar.getInstance();
    updateTime.setTimeZone(TimeZone.getDefault());
    updateTime.set(Calendar.HOUR_OF_DAY, 20);
    updateTime.set(Calendar.MINUTE, 30);

    Intent downloader = new Intent(context, AlarmReceiver.class);
    downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    // should be AlarmManager.INTERVAL_DAY (but changed to 15min for testing)
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent); 
    Log.d("MyActivity", "Set alarmManager.setRepeating to: " + updateTime.getTime().toLocaleString());
}

AlarmReceiver.java

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent dailyUpdater = new Intent(context, MyService.class);
        context.startService(dailyUpdater);
        Log.d("AlarmReceiver", "Called context.startService from AlarmReceiver.onReceive");
    }
}

MyService.java

public class MyService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "About to execute MyTask");
        new MyTask().execute();
        return Service.START_FLAG_REDELIVERY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class MyTask extends AsyncTask<String, Void, boolean> {
        @Override
        protected boolean doInBackground(String... strings) {
            Log.d("MyService - MyTask", "Calling doInBackground within MyTask");
            return false;
        }
    }
}

AndroidManifest.xml

<application ...>
    ...
    <service android:name="MyService"></service>
    <receiver android:name="AlarmReceiver"></receiver>
</application>

当我触发 中的 setRecurringAlarm 时MyActivity 日志按预期打印,类似地,每 15 分钟就会显示一次来自 AlarmReceiver 的日志。但是,我从未看到来自 MyService 的日志:(

我在日志中看到的示例:

DEBUG/MyActivity(688): Set alarmManager.setRepeating to: Jan 29, 2012 8:30:06 PM
DEBUG/AlarmReceiver(688): Called context.startService from AlarmReceiver.onReceive
DEBUG/AlarmReceiver(688): Called context.startService from AlarmReceiver.onReceive

似乎无法弄清楚我做错了什么 - 我对 Android Dev Docs 是在 AlarmReceiver 时我打电话context.startService(dailyUpdater) 应该依次调用 MyService 中的 onStartCommand,但情况似乎并非如此

我是什么 !做错了导致 MyService 根本无法启动?

I'm refactoring some code so that my app will pull data from a website once a day at a given time. From my research, it seems like AlarmManager is the most appropriate approach.

The tutorial I have been following is: http://mobile.tutsplus.com/tutorials/android/android-fundamentals-downloading-data-with-services/

So far, AlarmManager and the BroadcastReceiver seem to be working, however the Service never seems to start (ie. onStartCommand doesn't seem to be called)

Here are the important snippets of the code I have so far:

MyActivity.java

private void setRecurringAlarm(Context context) {
    Calendar updateTime = Calendar.getInstance();
    updateTime.setTimeZone(TimeZone.getDefault());
    updateTime.set(Calendar.HOUR_OF_DAY, 20);
    updateTime.set(Calendar.MINUTE, 30);

    Intent downloader = new Intent(context, AlarmReceiver.class);
    downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    // should be AlarmManager.INTERVAL_DAY (but changed to 15min for testing)
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent); 
    Log.d("MyActivity", "Set alarmManager.setRepeating to: " + updateTime.getTime().toLocaleString());
}

AlarmReceiver.java

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent dailyUpdater = new Intent(context, MyService.class);
        context.startService(dailyUpdater);
        Log.d("AlarmReceiver", "Called context.startService from AlarmReceiver.onReceive");
    }
}

MyService.java

public class MyService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "About to execute MyTask");
        new MyTask().execute();
        return Service.START_FLAG_REDELIVERY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class MyTask extends AsyncTask<String, Void, boolean> {
        @Override
        protected boolean doInBackground(String... strings) {
            Log.d("MyService - MyTask", "Calling doInBackground within MyTask");
            return false;
        }
    }
}

AndroidManifest.xml

<application ...>
    ...
    <service android:name="MyService"></service>
    <receiver android:name="AlarmReceiver"></receiver>
</application>

When I trigger the setRecurringAlarm in MyActivity the log prints as expected, similarly, every 15min the log from AlarmReceiver appears. However, I never see the log from MyService :(

Example of what I see in the logs:

DEBUG/MyActivity(688): Set alarmManager.setRepeating to: Jan 29, 2012 8:30:06 PM
DEBUG/AlarmReceiver(688): Called context.startService from AlarmReceiver.onReceive
DEBUG/AlarmReceiver(688): Called context.startService from AlarmReceiver.onReceive

Can't seem to figure out what I've done wrong - my understanding from the Android Dev Docs is that in AlarmReceiver when I call context.startService(dailyUpdater) that should in turn call onStartCommand in MyService, though that doesn't seem to be the case!

What am I doing wrong that is causing MyService to not start at all?

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

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

发布评论

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

评论(3

打小就很酷 2025-01-05 14:47:49

想通了!

MyService 应该扩展 IntentService 而不是 Service

通过此更改,这也意味着不应重写 onStartCommand ,而应重写 onHandleIntent (请参阅 IntentService

所以MyService现在看起来像这样:

public class MyService extends IntentService {

    public MyService() {
        super("MyServiceName");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d("MyService", "About to execute MyTask");
        new MyTask().execute();
    }

    private class MyTask extends AsyncTask<String, Void, boolean> {
        @Override
        protected boolean doInBackground(String... strings) {
            Log.d("MyService - MyTask", "Calling doInBackground within MyTask");
            return false;
        }
    }
}

注意:从文档中,onBind的默认实现返回null 所以不需要覆盖它。

有关扩展 IntentService 的更多信息:http://developer.android.com /guide/topics/fundamentals/services.html#ExtendingIntentService

Figured it out!

MyService should be extending IntentService instead of Service!

With this change, it also means that instead of overriding onStartCommand should be overriding onHandleIntent instead (see docs on IntentService)

So MyService now looks like this:

public class MyService extends IntentService {

    public MyService() {
        super("MyServiceName");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d("MyService", "About to execute MyTask");
        new MyTask().execute();
    }

    private class MyTask extends AsyncTask<String, Void, boolean> {
        @Override
        protected boolean doInBackground(String... strings) {
            Log.d("MyService - MyTask", "Calling doInBackground within MyTask");
            return false;
        }
    }
}

Note: From the docs, the default implementation of onBind returns null so no need to override it.

More information about extending IntentService: http://developer.android.com/guide/topics/fundamentals/services.html#ExtendingIntentService

人│生佛魔见 2025-01-05 14:47:49

如果您像这样改变您的意图,您可以让 AlarmManager 立即运行该服务,而不是通过 BroadcastReceiver:

//Change the intent
Intent downloader = new Intent(context, MyService.class);
    downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

//Change to getService()
PendingIntent pendingIntent = PendingIntent.getService(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);

这可能会解决您的问题!

You could get AlarmManager to run the Service straight away rather than going through a BroadcastReceiver, if you change your intent like this:

//Change the intent
Intent downloader = new Intent(context, MyService.class);
    downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

//Change to getService()
PendingIntent pendingIntent = PendingIntent.getService(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);

This may solve your problem!

青芜 2025-01-05 14:47:49

不要使用

Intent dailyUpdater = new Intent(context, MyService.class);

使用

Intent dailyUpdater = new Intent(this, MyService.class);

其他建议是启动服务直接来自警报,而不是发送广播并在广播接收器中启动服务。

Instead of using

Intent dailyUpdater = new Intent(context, MyService.class);

use

Intent dailyUpdater = new Intent(this, MyService.class);

Other suggestion is to start service directly from alarm rather than sending a broadcast and starting the service in broadcast receiver.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文