我正在使用Android开发人员培训网站上提供的示例代码(Scheduler.zip) - http://developer.android.com/training/scheduling/index.html
这是代码: -
MainActivity.java
/*
* Copyright 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.scheduler;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
/**
* This sample demonstrates how to schedule an alarm that causes a service to
* be started. This is useful when you want to schedule alarms that initiate
* long-running operations, such as retrieving a daily forecast.
* This particular sample retrieves content from the Google home page once a day and
* checks it for the search string "doodle". If it finds this string, that indicates
* that the page contains a custom doodle instead of the standard Google logo.
*/
public class MainActivity extends Activity {
SampleAlarmReceiver alarm = new SampleAlarmReceiver();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
// Menu options to set and cancel the alarm.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// When the user clicks START ALARM, set the alarm.
case R.id.start_action:
alarm.setAlarm(this);
return true;
// When the user clicks CANCEL ALARM, cancel the alarm.
case R.id.cancel_action:
alarm.cancelAlarm(this);
return true;
}
return false;
}
}
SampleAlarmReceiver.java
package com.example.android.scheduler;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.support.v4.content.WakefulBroadcastReceiver;
import java.util.Calendar;
/**
* When the alarm fires, this WakefulBroadcastReceiver receives the broadcast Intent
* and then starts the IntentService {@code SampleSchedulingService} to do some work.
*/
public class SampleAlarmReceiver extends WakefulBroadcastReceiver {
// The app's AlarmManager, which provides access to the system alarm services.
private AlarmManager alarmMgr;
// The pending intent that is triggered when the alarm fires.
private PendingIntent alarmIntent;
@Override
public void onReceive(Context context, Intent intent) {
// BEGIN_INCLUDE(alarm_onreceive)
/*
* If your receiver intent includes extras that need to be passed along to the
* service, use setComponent() to indicate that the service should handle the
* receiver's intent. For example:
*
* ComponentName comp = new ComponentName(context.getPackageName(),
* MyService.class.getName());
*
* // This intent passed in this call will include the wake lock extra as well as
* // the receiver intent contents.
* startWakefulService(context, (intent.setComponent(comp)));
*
* In this example, we simply create a new intent to deliver to the service.
* This intent holds an extra identifying the wake lock.
*/
Intent service = new Intent(context, SampleSchedulingService.class);
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, service);
// END_INCLUDE(alarm_onreceive)
}
// BEGIN_INCLUDE(set_alarm)
/**
* Sets a repeating alarm that runs once a day at approximately 8:30 a.m. When the
* alarm fires, the app broadcasts an Intent to this WakefulBroadcastReceiver.
* @param context
*/
public void setAlarm(Context context) {
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, SampleAlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
// Set the alarm's trigger time to 8:30 a.m.
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);
/*
* If you don't have precise time requirements, use an inexact repeating alarm
* the minimize the drain on the device battery.
*
* The call below specifies the alarm type, the trigger time, the interval at
* which the alarm is fired, and the alarm's associated PendingIntent.
* It uses the alarm type RTC_WAKEUP ("Real Time Clock" wake up), which wakes up
* the device and triggers the alarm according to the time of the device's clock.
*
* Alternatively, you can use the alarm type ELAPSED_REALTIME_WAKEUP to trigger
* an alarm based on how much time has elapsed since the device was booted. This
* is the preferred choice if your alarm is based on elapsed time--for example, if
* you simply want your alarm to fire every 60 minutes. You only need to use
* RTC_WAKEUP if you want your alarm to fire at a particular date/time. Remember
* that clock-based time may not translate well to other locales, and that your
* app's behavior could be affected by the user changing the device's time setting.
*
* Here are some examples of ELAPSED_REALTIME_WAKEUP:
*
* // Wake up the device to fire a one-time alarm in one minute.
* alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
* SystemClock.elapsedRealtime() +
* 60*1000, alarmIntent);
*
* // Wake up the device to fire the alarm in 30 minutes, and every 30 minutes
* // after that.
* alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
* AlarmManager.INTERVAL_HALF_HOUR,
* AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
*/
// Set the alarm to fire at approximately 8:30 a.m., according to the device's
// clock, and to repeat once a day.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 2*60*1000, alarmIntent);
// Enable {@code SampleBootReceiver} to automatically restart the alarm when the
// device is rebooted.
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
// END_INCLUDE(set_alarm)
/**
* Cancels the alarm.
* @param context
*/
// BEGIN_INCLUDE(cancel_alarm)
public void cancelAlarm(Context context) {
// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
alarmMgr.cancel(alarmIntent);
}
// Disable {@code SampleBootReceiver} so that it doesn't automatically restart the
// alarm when the device is rebooted.
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
// END_INCLUDE(cancel_alarm)
}
SampleBootReceiver.java
package com.example.android.scheduler;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* This BroadcastReceiver automatically (re)starts the alarm when the device is
* rebooted. This receiver is set to be disabled (android:enabled="false") in the
* application's manifest file. When the user sets the alarm, the receiver is enabled.
* When the user cancels the alarm, the receiver is disabled, so that rebooting the
* device will not trigger this receiver.
*/
// BEGIN_INCLUDE(autostart)
public class SampleBootReceiver extends BroadcastReceiver {
SampleAlarmReceiver alarm = new SampleAlarmReceiver();
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
alarm.setAlarm(context);
}
}
}
//END_INCLUDE(autostart)
SampleSchedulingService.java
package com.example.android.scheduler;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* This {@code IntentService} does the app's actual work.
* {@code SampleAlarmReceiver} (a {@code WakefulBroadcastReceiver}) holds a
* partial wake lock for this service while the service does its work. When the
* service is finished, it calls {@code completeWakefulIntent()} to release the
* wake lock.
*/
public class SampleSchedulingService extends IntentService {
public SampleSchedulingService() {
super("SchedulingService");
}
public static final String TAG = "Scheduling Demo";
// An ID used to post the notification.
public static final int NOTIFICATION_ID = 1;
// The string the app searches for in the Google home page content. If the app finds
// the string, it indicates the presence of a doodle.
public static final String SEARCH_STRING = "doodle";
// The Google home page URL from which the app fetches content.
// You can find a list of other Google domains with possible doodles here:
// http://en.wikipedia.org/wiki/List_of_Google_domains
public static final String URL = "http://www.google.com";
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
@Override
protected void onHandleIntent(Intent intent) {
// BEGIN_INCLUDE(service_onhandle)
// The URL from which to fetch content.
String urlString = URL;
String result ="";
// Try to connect to the Google homepage and download content.
try {
result = loadFromNetwork(urlString);
} catch (IOException e) {
Log.i(TAG, getString(R.string.connection_error));
}
// If the app finds the string "doodle" in the Google home page content, it
// indicates the presence of a doodle. Post a "Doodle Alert" notification.
if (result.indexOf(SEARCH_STRING) != -1) {
sendNotification(getString(R.string.doodle_found));
Log.i(TAG, "Found doodle!!");
} else {
sendNotification(getString(R.string.no_doodle));
Log.i(TAG, "No doodle found. :-(");
}
// Release the wake lock provided by the BroadcastReceiver.
SampleAlarmReceiver.completeWakefulIntent(intent);
// END_INCLUDE(service_onhandle)
}
// Post a notification indicating whether a doodle was found.
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.doodle_alert))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
//
// The methods below this line fetch content from the specified URL and return the
// content as a string.
//
/** Given a URL string, initiate a fetch operation. */
private String loadFromNetwork(String urlString) throws IOException {
InputStream stream = null;
String str ="";
try {
stream = downloadUrl(urlString);
str = readIt(stream);
} finally {
if (stream != null) {
stream.close();
}
}
return str;
}
/**
* Given a string representation of a URL, sets up a connection and gets
* an input stream.
* @param urlString A string representation of a URL.
* @return An InputStream retrieved from a successful HttpURLConnection.
* @throws IOException
*/
private InputStream downloadUrl(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Start the query
conn.connect();
InputStream stream = conn.getInputStream();
return stream;
}
/**
* Reads an InputStream and converts it to a String.
* @param stream InputStream containing HTML from www.google.com.
* @return String version of InputStream.
* @throws IOException
*/
private String readIt(InputStream stream) throws IOException {
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
for(String line = reader.readLine(); line != null; line = reader.readLine())
builder.append(line);
reader.close();
return builder.toString();
}
}
我必须首先将android-support-v4.jar文件添加到构建路径才能使其正常工作。
我每隔2分钟收到通知,但点击“取消闹钟”按钮后,闹钟就不会被取消。
所以,我尝试在cancelAlarm函数中删除if条件,但之后我得到了一个java.nullpointerexception。
基本上,alarmMgr变为空。
但是,我无法理解为什么。
另外,由于这是一个示例代码,我认为其中一定没有错误,所以我必须错过一些东西。
答案 0 :(得分:0)
我认为这是因为alarmManager(alarmMgr)的实例可能未初始化,因为它在setAlarm中初始化。所以你必须在cancelAlarm方法中初始化它,以防它为空。
SampleAlarmReceiver.java:
public void cancelAlarm(Context context) {
if (alarmMgr==null) {
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
}
Intent intent = new Intent(context, SampleAlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0 , intent, 0);
try{
alarmMgr.cancel(alarmIntent);
Log.e("Alarma cancelada", action );
}catch (Exception e) {
Log.e("Error alarma", "AlarmManager update was not canceled. " + e.toString());
}
.
.
.