2

是否可以在不使用服务的应用程序的情况下使用 AlarmManager 来运行警报。AlarmManager 必须让设备退出睡眠模式并在 onReceive 中执行我的代码。实际上,我在这里看到的每个代码示例都显示了正在使用的服务。然而,Android 文档并没有提到需要服务。

4

3 回答 3

1

这是一个工作示例,

activity_alarm_manager.xml 文件的代码

<linearlayout android:layout_height="match_parent"
   android:layout_width="match_parent" android:orientation="vertical"
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools">

   <button android:id="@+id/btStart" android:layout_height="wrap_content"
     android:layout_width="match_parent" android:onclick="startRepeatingTimer"
     android:padding="@dimen/padding_medium" android:text="@string/btStart"  
     tools:context=".WidgetAlarmManagerActivity"/>
   <button android:id="@+id/btCancel" android:layout_height="wrap_content"
     android:layout_width="match_parent" android:onclick="cancelRepeatingTimer" 
     android:padding="@dimen/padding_medium" android:text="@string/btCancel"
     tools:context=".WidgetAlarmManagerActivity"/>
    <button android:id="@+id/btOneTime" android:layout_height="wrap_content"
    android:layout_width="match_parent" android:onclick="onetimeTimer"
    android:padding="@dimen/padding_medium" android:text="@string/btOneTime"  
    tools:context=".WidgetAlarmManagerActivity"/>
  </linearlayout>

BroadcastReceiver的代码,

public class AlarmManagerBroadcastReceiver extends BroadcastReceiver {

 final public static String ONE_TIME = "onetime";

 @Override
 public void onReceive(Context context, Intent intent) {
   PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YOUR TAG");
         //Acquire the lock
         wl.acquire();

         //You can do the processing here.
         Bundle extras = intent.getExtras();
         StringBuilder msgStr = new StringBuilder();

         if(extras != null && extras.getBoolean(ONE_TIME, Boolean.FALSE)){
          //Make sure this intent has been sent by the one-time timer button.
          msgStr.append("One time Timer : ");
         }
         Format formatter = new SimpleDateFormat("hh:mm:ss a");
         msgStr.append(formatter.format(new Date()));

         Toast.makeText(context, msgStr, Toast.LENGTH_LONG).show();

         //Release the lock
         wl.release();
 }

 public void SetAlarm(Context context)
    {
        AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
        intent.putExtra(ONE_TIME, Boolean.FALSE);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
        //After after 5 seconds
        am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 5 , pi);
    }

    public void CancelAlarm(Context context)
    {
        Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }

    public void setOnetimeTimer(Context context){
     AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
        intent.putExtra(ONE_TIME, Boolean.TRUE);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
        am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pi);
    }
}

AndroidManifest.xml 的代码

<manifest android:versioncode="1" android:versionname="1.0"
       package="com.rakesh.alarmmanagerexample"
       xmlns:android="http://schemas.android.com/apk/res/android">

   <uses-sdk android:minsdkversion="10" android:targetsdkversion="15"/>
   <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <application android:icon="@drawable/ic_launcher"
       android:label="@string/app_name" android:theme="@style/AppTheme">
        <activity android:label="@string/title_activity_alarm_manager"
           android:name="com.rakesh.alarmmanagerexample.AlarmManagerActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
        </activity>
        <receiver android:name="com.rakesh.alarmmanagerexample.AlarmManagerBroadcastReceiver">
        </receiver>
    </application>
</manifest>

AlarmManagerActivity.java 文件的代码

public class AlarmManagerActivity extends Activity {

 private AlarmManagerBroadcastReceiver alarm;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alarm_manager);
        alarm = new AlarmManagerBroadcastReceiver();
    }

    @Override
 protected void onStart() {
  super.onStart();
 }

    public void startRepeatingTimer(View view) {
     Context context = this.getApplicationContext();
     if(alarm != null){
      alarm.SetAlarm(context);
     }else{
      Toast.makeText(context, "Alarm is null", Toast.LENGTH_SHORT).show();
     }
    }

    public void cancelRepeatingTimer(View view){
     Context context = this.getApplicationContext();
     if(alarm != null){
      alarm.CancelAlarm(context);
     }else{
      Toast.makeText(context, "Alarm is null", Toast.LENGTH_SHORT).show();
     }
    }

    public void onetimeTimer(View view){
     Context context = this.getApplicationContext();
     if(alarm != null){
      alarm.setOnetimeTimer(context);
     }else{
      Toast.makeText(context, "Alarm is null", Toast.LENGTH_SHORT).show();
     }
    }

 @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_widget_alarm_manager, menu);
        return true;
    }
}

来自Github的参考链接

于 2013-04-20T10:45:52.107 回答
0

我认为Activity通过传递它来设置周期性事件Context并不重要,并且传递哪个上下文似乎并不重要。

passcontext仅用于获取PendingIntentfromPendingIntent.getBroadcast和 from 查看4.2.2 的源

/**
 * Retrieve a PendingIntent that will perform a broadcast, like calling
 * {@link Context#sendBroadcast(Intent) Context.sendBroadcast()}.
 *
 * @param context The Context in which this PendingIntent should perform
 * the broadcast.
 * @param requestCode Private request code for the sender (currently
 * not used).
 * @param intent The Intent to be broadcast.
 * @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
 * {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
 * or any of the flags as supported by
 * {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
 * of the intent that can be supplied when the actual send happens.
 *
 * @return Returns an existing or new PendingIntent matching the given
 * parameters.  May return null only if {@link #FLAG_NO_CREATE} has been
 * supplied.
 */
public static PendingIntent getBroadcast(Context context, int requestCode,
        Intent intent, int flags) {
    return getBroadcastAsUser(context, requestCode, intent, flags,
            new UserHandle(UserHandle.myUserId()));
}

/**
 * @hide
 * Note that UserHandle.CURRENT will be interpreted at the time the
 * broadcast is sent, not when the pending intent is created.
 */
public static PendingIntent getBroadcastAsUser(Context context, int requestCode,
        Intent intent, int flags, UserHandle userHandle) {
    String packageName = context.getPackageName();
    String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
            context.getContentResolver()) : null;
    try {
        intent.setAllowFds(false);
        IIntentSender target =
            ActivityManagerNative.getDefault().getIntentSender(
                ActivityManager.INTENT_SENDER_BROADCAST, packageName,
                null, null, requestCode, new Intent[] { intent },
                resolvedType != null ? new String[] { resolvedType } : null,
                flags, null, userHandle.getIdentifier());
        return target != null ? new PendingIntent(target) : null;
    } catch (RemoteException e) {
    }
    return null;
}

你可以看到,passedcontext仅用于获取包名和解析类型,并没有存储在PendingIntent或任何可能导致一些问题和泄漏的东西中。

于 2013-04-20T11:16:08.427 回答
0

你可以:

  1. 给出AlarmManager一个PendingIntent带有 Intent 的特定过滤器BroadCastReciever

  2. 在应用程序的清单中声明此接收器以及意图过滤器。

  3. 该接收器onRecieve()将被调用AlarmManager

不涉及任何服务。

于 2013-04-20T08:24:20.510 回答