15

I've poured through a dozen tutorials and forum answers about this problem, but still haven't been able to get some working code together. I'll try to keep the question straightforward:

How do you use AlarmManager (in the Android API) to start an Activity at a given time? Any solution to this problem will do.

My latest attempt to achieve this is below.

(Imports omitted. I expect MyActivity to start 3 seconds after the program is opened, which it doesn't. There are no error messages to speak of.)

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);
    }
}

Any advice would be appreciated.

Please note: I've got myReceiver in the manifest already

BenLambell
  • 354
  • 1
  • 3
  • 9
  • 2
    Did you register the receiver in your AndroidManifest? –  Aug 13 '11 at 11:10
  • Sorry, should have mentioned that. With the line , yes I did. Let me know if that's the wrong line. – BenLambell Aug 13 '11 at 19:27
  • For the alarm to launch an activity rather than create a broadcast, make sure you are using `PendingIntent.getActivity(...)` instead of `PendingIntent.getBroadcast(...)`. – ban-geoengineering Apr 15 '19 at 20:17

8 Answers8

8

In case someone else stumbles upon this - here's some working code (Tested on 2.3.3 emulator):

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>

Issues with BenLambell's code :

  • EITHER:
    • Move the receiver to it's own .java file or
    • make the inner class static - so it can be accessed from outside
  • Receiver is not declared correctly in the manifest:
    • if it's an inner class in MainActivity use: <receiver android:name="package.name.MainActivity$AlarmReceiver" ></receiver>
    • if it's in a separate file: <receiver android:name="package.name.AlarmReceiver" ></receiver>

If your intention is to display a dialog in the receiver's onReceive (like me): that's not allowed - only activities can start dialogs. This can be achieved with a dialog activity.

You can directly call an activity with the 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);
Community
  • 1
  • 1
Dean Panayotov
  • 332
  • 4
  • 16
  • 1
    Can directly calling an activity with AlarmManager launch an activity or bring it to front if the app is in the background or closed? I'm trying with no success. – Dpedrinha Sep 11 '19 at 22:25
4

How do you use AlarmManager (in the Android API) to start an Activity at a given time?

Supply a PendingIntent to the set() call that identifies the activity to start up. Or, do what you're doing, which should work just fine.

This sample project is a bit elaborate, because it's 19 tutorials deep into one of my books, but if you look at classes like EditPreferences, OnBootReceiver, and OnAlarmReceiver, you will see the same basic recipe that you're using above. In this case, I could have just used a getActivity() PendingIntent, but the tutorial after this one gives the user a choice of launching an activity or displaying a Notification, so a BroadcastReceiver makes more sense.

Look for warnings in addition to errors in LogCat. Most likely, your receiver or activity is not in your manifest.

Note that popping up an activity out of the middle of nowhere is generally not a good idea. Quoting myself from the book in question:

Displaying the lunchtime alarm via a full-screen activity certainly works, and if the user is looking at the screen, it will get their attention. However, it is also rather disruptive if they happen to be using the phone right that instant. For example, if they are typing a text message while driving, your alarm activity popping up out of nowhere might distract them enough to cause an accident. So, in the interest of public safety, we should give the user an option to have a more subtle way to remind them to have lunch.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks for the speedy response - I've actually seen your tutorial already. I tried substituting Intent intent = new Intent(context, MyActivity.class); // CORRECT PendingIntent pending = PendingIntent.getActivity( context, 0, intent, 0 ); // CORRECT – BenLambell Aug 13 '11 at 19:49
  • Thanks for the speedy response - I've actually seen your tutorial already (and put the receiver in the manifest). I tried substituting in Intent intent = new Intent(context, MyActivity.class); PendingIntent pending = PendingIntent.getActivity( context, 0, intent, 0 ); but still don't get any evidence of MyActivity running. However, I do get the following log message: (ActivityManager) Starting: Intent { flg=0x4 cmp=com.ben/.MyActivity (has extras) } from pid -1 – BenLambell Aug 13 '11 at 19:58
  • Then there's a 'No keyboard for id 0' warning and a 'request time failed: Java.net.SocketException: Address family not supported by protocol' debug message.

    Does this mean that MyActivity is being started? And if so, why doesn't its onCreate() run?
    – BenLambell Aug 13 '11 at 19:59
  • @BenLambell: Beats me. If the activity is in the manifest, it should be starting. Perhaps it is crashing somewhere in `onCreate()` -- you should see a stack trace, though. – CommonsWare Aug 14 '11 at 11:30
  • To double check, is it definitely true that one can send any kind of PendingIntent to AlarmManager's family of 'set..' functions? One would hope so, otherwise encapsulation would be broken, but the Android documentation hints very strongly that it should be a broadcast intent and fielded by a BroadcastReceiver. Is this misleading? Using the result of a PendingIntent.getActivity() seems to work fine and give the results I want, but I want to know whether this is riskily unorthodox, or whether there are known issues/risks with non-broadcast intents. – JulianSymes Feb 24 '13 at 15:13
  • 1
    @user1681572: "Is this misleading?" -- if you are using a `_WAKEUP` alarm, the only guarantee you have about the device being awake is that it will be awake during the call to `onReceive()`. Other than that one scenario, I know nothing that is especially magic about using a `getBroadcast()` `PendingIntent` with `AlarmManager` compared to any other type of `PendingIntent`. – CommonsWare Feb 24 '13 at 15:15
  • 1
    `if they are typing a text message while driving`? People should not use their phone/tablet while driving... – Dediqated Sep 28 '16 at 09:27
  • Thanks @CommonsWare for this tutorial, It seems to me there are many apps in this project, and I'd like to know how to separate the specific folder into an installable app (separate Module??) in order to check the code on a physical device, I've found nothing on how to achieve this anywhere. Also, many dependencies like Geo does not exist in the Android library for some reason when setting dependencies to Java 11 and min SDK 28. This tutorial is from 2013?? so I don't understand... – Delark Mar 01 '23 at 16:06
  • 1
    @Delark: The aforementioned sample code is a decade old. I do not recommend attempting to build it directly. – CommonsWare Mar 01 '23 at 18:06
  • Thanks @CommonsWare, I guess I'll need to dig a little bit more, it seems to b a common occurrence in tech that discussions about tech spec knowledge peak a short period after an initial trend peak, and then this information is buried. What I would've expected is for this (Alarm API) at this point to be a simple to use module(I guess this is happening privately, hence the radio silence),but checking the documentation it seems to still be somewhat cumbersome. What's worst the interfaces have been constantly changing and I see no one openly developing on this new interface, maybe Im just lazy... – Delark Mar 01 '23 at 18:54
1

add this in your android mainifest file and it will hopefully work

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

In my experience you can achieve this without broadcast receiver, just use PendingIntent.getActivity() instead of 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);   
}

I've tested this code on android O but I'm not sure about other android versions please inform me if this doesn't work on any other android version.

Amir Dadgari
  • 531
  • 5
  • 13
1

Main Problem : if you close completely you're app and expect to start you're activity after 3 seconds, you wrong. because when you close you're app , you're app cant receive broadcast, for solve this problem use services instead of broadcasts.

Point: when you're service would ran ,you cant start your activity if your app wouldn't in foreground.

Solution: I think when your service started you can again set Alarmmanager to start your activity with PendingIntent for just now.

Remember :

  1. When you create your intent for pass it to pendingIntent add the FLAG_ACTIVITY_NEW_TASK to it.
  2. For this PendingIntent use PendingIntent.getActivity() method and for the first PendingIntent use PendingIntent.getService() method.

I hope this help you.

baitmbarek
  • 2,440
  • 4
  • 18
  • 26
moein shojaei
  • 55
  • 1
  • 6
1

I had this problem too long ago to know which answer is correct, but thank you to everyone for their responses. I'm self-answering so the question isn't still open.

BenLambell
  • 354
  • 1
  • 3
  • 9
0

you are not sending any broadcast for the receiver to receiver and further more it lokks like u want a splash screen or something like that for that purpose u can start a new thread wait for some sec then start ur activity in that and for that time period u can do what ever u want on the UI thread ...

0

According to Java convention class name begin with Capital letter.So change your

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

Then add your receiver in the manifest file like the below.

<application 
------------
<receiver android:name="MyReceiver"></receiver>
---------------------
</application>
jainal
  • 2,973
  • 2
  • 20
  • 18
  • I've adopted proper Java convention, just in case it matters. Already had correct line in manifest though (I've tried using .MyReceiver and MyReceiver as the android:name - sources I've seen seem to do either). In any case, this doesn't fix the problem, but thanks for your suggestion. – BenLambell Aug 13 '11 at 19:43