AlarmManager,BroadcastReceiver和Service无法正常工作

时间:2012-01-29 12:44:49

标签: android broadcastreceiver alarmmanager android-pendingintent

我正在重构一些代码,以便我的应用程序每天在给定时间从网站提取数据。从我的研究来看,似乎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的理解是AlarmReceivercontext.startService(dailyUpdater)打电话给onStartCommand时应该调用MyServiceMyService中,虽然情况似乎并非如此!

我做错了什么导致{{1}}根本无法启动?

3 个答案:

答案 0 :(得分:15)

想出来了!

MyService 应该扩展 IntentService ,而不是服务

通过此更改,这也意味着代替覆盖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

答案 1 :(得分:0)

如果你改变你的意图,你可以让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);

这可以解决您的问题!

答案 2 :(得分:0)

而不是使用

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

使用

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

其他建议是直接从闹钟开始服务,而不是发送广播并在广播接收器中启动服务。