Monday, May 9, 2011

Using AlarmManager to start a Scheduled Activity

In this exercise, we are going to implement alarmManager to start a Scheduled Activity.

The main activity(AndroidScheduledActivity.java) start a AlarmManager to trigger BroadcastReceiver(MyScheduledReceiver.java) repeatly. In the onReceive() method of MyScheduledReceiver, it start another activity(MyScheduledActivity.java) indirectly. Such that the activity(MyScheduledActivity.java) will be start in scheduled interval.

main.xml, layout of the main activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
<TextView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="@string/hello"
  />
<Button
  android:id="@+id/start"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="Start Scheduled Activity"
  />
</LinearLayout>


main activity, AndroidScheduledActivity.java
package com.exercise.AndroidScheduledActivity;

import java.util.Calendar;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class AndroidScheduledActivity extends Activity {

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      Button buttonStart = (Button)findViewById(R.id.start);
      buttonStart.setOnClickListener(new Button.OnClickListener(){

  @Override
  public void onClick(View arg0) {
   // TODO Auto-generated method stub
    Intent myIntent = new Intent(getBaseContext(),
      MyScheduledReceiver.class);

    PendingIntent pendingIntent
     = PendingIntent.getBroadcast(getBaseContext(),
       0, myIntent, 0);
  
    AlarmManager alarmManager
      = (AlarmManager)getSystemService(ALARM_SERVICE);
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.add(Calendar.SECOND, 10);
    long interval = 60 * 1000; //
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
      calendar.getTimeInMillis(), interval, pendingIntent);
    finish();
  }});
  }

}


BroadcastReceiver, MyScheduledReceiver.java

package com.exercise.AndroidScheduledActivity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyScheduledReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
 // TODO Auto-generated method stub

 Intent scheduledIntent = new Intent(context, MyScheduledActivity.class);
 scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 context.startActivity(scheduledIntent);

}

}


Layout of the scheduled activity, layout_scheduledactivity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
<TextView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="--- Scheduled Activity ---"
  />
<Button
  android:id="@+id/dismiss"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:text="Dismiss"
  />
</LinearLayout>


Scheduled activity, MyScheduledActivity.java
package com.exercise.AndroidScheduledActivity;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MyScheduledActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onCreate(savedInstanceState);
 setContentView(R.layout.layout_scheduledactivity);

 Button buttonDismiss = (Button)findViewById(R.id.dismiss);

 buttonDismiss.setOnClickListener(new Button.OnClickListener(){

  @Override
  public void onClick(View arg0) {
   // TODO Auto-generated method stub
   finish();
  }});
}

}


Finally, update AndroidManifest.xml with new activity of MyScheduledActivity, and new receiver of MyScheduledReceiver.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.exercise.AndroidScheduledActivity"
    android:versionCode="1"
    android:versionName="1.0">
  <uses-sdk android:minSdkVersion="4" />

  <application android:icon="@drawable/icon" android:label="@string/app_name">
      <activity android:name=".AndroidScheduledActivity"
                android:label="@string/app_name">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
      </activity>
      <activity android:name=".MyScheduledActivity" />
      <receiver android:process=":remote"
                android:name="MyScheduledReceiver" />
  </application>
</manifest>


download filesDownload the files.

Next:
- Cancel Alarm using alarmManager.cancel(pendingIntent)

Related Article:
- A simple example of Alarm Service, using AlarmManager

5 comments:

Calin Grecu said...

You do not need a broadcast receiver for your example. A PendingIntent created with PendingIntent.getActivity would suffice. This would invoke the activity directly.

Gui HGO said...

whats is difference between i use BroadcastReceiver and Service ??

Avinash Singh said...

I have created my own alarm app but the problem is that when I am scheduling my alarm then
it ring after the allocated time with difference of 3 min.

Andr.oid Eric said...

hello Avinash Singh,

Yes.

Note: Beginning in API 19, the trigger time passed to this method is treated as inexact: the alarm will not be delivered before this time, but may be deferred and delivered some time later. The OS will use this policy in order to "batch" alarms together across the entire system, minimizing the number of times the device needs to "wake up" and minimizing battery use. In general, alarms scheduled in the near future will not be deferred as long as alarms scheduled far in the future.

With the new batching policy, delivery ordering guarantees are not as strong as they were previously. If the application sets multiple alarms, it is possible that these alarms' actual delivery ordering may not match the order of their requested delivery times. If your application has strong ordering requirements there are other APIs that you can use to get the necessary behavior; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent).

Applications whose targetSdkVersion is before API 19 will continue to get the previous alarm behavior: all of their scheduled alarms will be treated as exact.

https://developer.android.com/reference/android/app/AlarmManager.html

Avinash Singh said...

thank u eric