如何使用AlarmManager在Android中启动活动(Activity)?

15

我已经浏览了十几个关于这个问题的教程和论坛答案,但仍然无法组合出一些可以工作的代码。我会尽量保持问题简单明了:

如何使用Android API中的AlarmManager在指定时间启动一个Activity?任何解决此问题的方法都可以。

我最近尝试的代码如下所示。(省略了导入部分)我希望MyActivity在程序打开后3秒钟开始运行,但它没有。也没有任何错误信息。

public class AndroidTest2Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Context context = this;//.getApplicationContext();

        AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); // CORRECT
        Intent intent = new Intent(context, myReceiver.class); // CORRECT
        PendingIntent pending = PendingIntent.getBroadcast( context, 0, intent, 0 ); // CORRECT
        manager.set( AlarmManager.RTC, System.currentTimeMillis() + 3000, pending ); // CORRECT

        setContentView(R.layout.main);
    }
}

public class myReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        Intent i=new Intent(context, myActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(i);
    }
}

public class myActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("", "Elusive success");
        setContentView(R.layout.main);
    }
}

希望能得到任何建议。

请注意:我已经在清单文件中添加了myReceiver。


2
你在 AndroidManifest 中注册了接收器吗? - user658042
抱歉,我应该提到了。使用<receiver android:name=".myReceiver"></receiver>这行代码,是的,我用了。如果这不是正确的代码,请告诉我。 - BenLambell
为了使闹钟启动一个活动而不是创建广播,请确保使用PendingIntent.getActivity(...)而不是PendingIntent.getBroadcast(...) - ban-geoengineering
8个回答

8

如果有其他人遇到同样的问题,这里有一些可行的代码(在2.3.3模拟器上测试通过):

public final void setAlarm(int seconds) {
    // create the pending intent
    Intent intent = new Intent(MainActivity.this, AlarmReceiver.class);
    // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0,
            intent, 0);
    // get the alarm manager, and scedule an alarm that calls the receiver
    ((AlarmManager) getSystemService(ALARM_SERVICE)).set(
            AlarmManager.RTC, System.currentTimeMillis() + seconds
                    * 1000, pendingIntent);
    Toast.makeText(MainActivity.this, "Timer set to " + seconds + " seconds.",
            Toast.LENGTH_SHORT).show();
}

public static class AlarmReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        Log.d("-", "Receiver3");
    }
}

AndroidManifest.xml:

    <receiver android:name="com.example.test.MainActivity$AlarmReceiver" >
    </receiver>

BenLambell的代码存在以下问题:

  • 要么将接收器移到自己的.java文件中,要么将内部类设置为静态 - 这样可以从外部访问。
  • 在清单文件中没有正确声明接收器:
    • 如果它是MainActivity中的内部类,请使用: <receiver android:name="package.name.MainActivity$AlarmReceiver" ></receiver>
    • 如果它在一个单独的文件中: <receiver android:name="package.name.AlarmReceiver" ></receiver>

如果您的意图是在接收器的onReceive中显示对话框(像我一样),那是不允许的 - 只有活动才能启动对话框。这可以通过对话框活动来实现。

您可以直接使用AlarmManager调用活动:

Intent intent = new Intent(MainActivity.this, TriggeredActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager) getSystemService(ALARM_SERVICE)).set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + seconds * 1000, pendingIntent);

1
如果应用在后台或关闭状态,使用AlarmManager直接调用活动能否启动活动或将其置于前台?我尝试了但没有成功。 - Dpedrinha

4
如何使用AlarmManager(在Android API中)在指定时间启动Activity?
提供一个PendingIntentset()调用,以标识要启动的Activity。或者,继续你正在做的事情,这应该可以正常工作。 此示例项目有点复杂,因为它深入到我的一本书中的第19个教程,但是如果您查看像EditPreferencesOnBootReceiverOnAlarmReceiver这样的类,您将看到与上面使用的相同的基本配方。在这种情况下,我本可以只使用一个getActivity()PendingIntent,但是在此之后的教程中,用户可以选择启动Activity或显示Notification,因此BroadcastReceiver更合适。
在LogCat中除了错误外还要查找警告。最可能的情况是,您的接收器或Activity不在清单文件中。
请注意,突然弹出一个活动通常不是一个好主意。引用自相关书籍的我自己所说:
通过全屏活动显示午餐时间闹钟确实有效,如果用户正在查看屏幕,则会引起他们的注意。但是,如果他们恰好在使用手机时,这也会非常破坏性。例如,如果他们在开车时输入短信,你的闹钟活动突然跳出来可能会分散他们的注意力,从而导致事故发生。因此,为了公共安全起见,我们应该给用户提供一种更加微妙的方式来提醒他们午餐时间到了。

感谢您的迅速回复 - 我已经看过您的教程了(并将接收器放在清单中)。我尝试替换为Intent intent = new Intent(context, MyActivity.class); PendingIntent pending = PendingIntent.getActivity( context, 0, intent, 0 );但仍然没有任何证据表明MyActivity正在运行。但是,我确实收到以下日志消息:(ActivityManager) Starting: Intent { flg=0x4 cmp=com.ben/.MyActivity (has extras) } from pid -1 - BenLambell
1
如果你正在使用一个 _WAKEUP 闹钟,唯一可以保证设备处于唤醒状态的时间是在 onReceive() 被调用时。除了这种情况,我不知道使用 AlarmManager 和任何其他类型的 PendingIntent 相比,有什么特别神奇的地方。 - CommonsWare
1
如果他们在开车时打字发短信?人们不应该在驾驶时使用手机/平板电脑... - Dediqated
1
@Delark:上述示例代码已有十年之久。我不建议直接尝试构建它。 - CommonsWare
1
@Delark:上述示例代码已经有十年的历史了。我不建议直接尝试构建它。 - CommonsWare
显示剩余6条评论

1
根据我的经验,您可以在不使用广播接收器的情况下实现此目标,只需使用PendingIntent.getActivity()而不是getbroadcast()即可。
private void setReminder(){

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
            Calendar startTime = Calendar.getInstance();
            startTime.add(Calendar.MINUTE, 1);
            Intent intent = new Intent(ReminderActivity.this, ReminderActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            PendingIntent pendingIntent = PendingIntent.getActivity(ReminderActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            alarmManager.set(AlarmManager.RTC, startTime.getTimeInMillis(), pendingIntent);   
}

我已经在 Android O 上测试了这段代码,但不确定其他 Android 版本是否可用,请告知我是否在其他 Android 版本上无法正常工作。


1

我也遇到了这个问题很久了,已经不知道哪个答案是正确的了,但感谢每个人的回复。我自己回答一下,这样问题就不会还是未解决的状态了。


1
主要问题: 如果您完全关闭应用程序并期望在3秒后启动活动,则是错误的。因为当您关闭应用程序时,您的应用程序无法接收广播,解决此问题,请改用服务而不是广播。 要点: 当您的服务运行时,如果您的应用程序不在前台,则无法启动您的活动。 解决方案: 我认为当您的服务启动时,可以再次设置Alarmmanager以使用PendingIntent立即启动您的活动。 请记住:
  1. 当创建用于传递给pendingIntent的意图时,请将FLAG_ACTIVITY_NEW_TASK添加到其中。
  2. 对于此PendingIntent,请使用PendingIntent.getActivity()方法,并对于第一个PendingIntent,请使用PendingIntent.getService()方法。
我希望这可以帮助您。

1

将此添加到您的Android清单文件中,希望它能够正常工作。

<activity android:name=".MyReceiver" />
        <receiver android:name=".MyReceiver"> </receiver>

0

根据Java的约定,类名应以大写字母开头。因此请更改您的

"myReceiver" to "MyReceiver" and  "myActivity" to "MyActivity".

然后在清单文件中添加接收器,就像下面这样。

<application 
------------
<receiver android:name="MyReceiver"></receiver>
---------------------
</application>

我已经采用了适当的Java约定,以防有影响。虽然清单中已经有正确的行,但我尝试使用.MyReceiver和MyReceiver作为android:name - 我看到的来源似乎都这样做。无论如何,这并没有解决问题,但感谢您的建议。 - BenLambell

0

你没有发送任何广播给接收器,而且看起来你想要一个启动画面或类似的东西。为此,你可以启动一个新线程等待几秒钟,然后在其中启动你的活动,并在此期间可以在UI线程上做任何你想做的事情...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接