Android – Scheduling an application to start later.

Recently I have been working on a simple application that should have the ability to start itself after a period of time, after the application is closed. Hopefully, it turned out that this is quite simple to implement, and to achieve this, the AlarmManager in conjuction with a BroadcastReceiver can be used.

The basic idea is as follows: the AlarmManger registers an intent, when the alarm goes off, the intent that had been registered automatically will start the target application if it is not already running. The BroadcastReceiver will be listening for that intent, and when the intent is received, it will start the desired activity from the application.

The broadcast receiver implementation looks like this:


public class OnAlarmReceive extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {

     Log.d(Globals.TAG, "BroadcastReceiver, in onReceive:");

     // Start the MainActivity
     Intent i = new Intent(context, MainActivity.class);
     i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     context.startActivity(i);
  }
}

Register the OnAlarmReceive in the AndroidManifest file:


<application
   android:icon="@drawable/ic_launcher"
   android:label="@string/app_name" >

   // ......

   <receiver
      android:name=".OnAlarmReceive" />

</application>

And finally, here’s how to setup the alarm:

/**
* Sets up the alarm
*
* @param seconds
*            - after how many seconds from now the alarm should go off
*/
private void setupAlarm(int seconds) {
  AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
  Intent intent = new Intent(getBaseContext(), OnAlarmReceive.class);
  PendingIntent pendingIntent = PendingIntent.getBroadcast(
     MainActivity.this, 0, intent,
     PendingIntent.FLAG_UPDATE_CURRENT);

  Log.d(Globals.TAG, "Setup the alarm");

  // Getting current time and add the seconds in it
  Calendar cal = Calendar.getInstance();
  cal.add(Calendar.SECOND, seconds);

  alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);

  // Finish the currently running activity
  MainActivity.this.finish();
}

The last line from the code – finishing the current activity – is optional of course, but in case you need to finish the activity, here’s how to do.

For a live demo of the code, download the Amazing Cracked Screen application and see how it works. There you have the possibility to set up the delay in seconds when the application should start later and show the “broken” screen.

Writing and Reading from SharedPreferences

SharedPreferences class allows you to save and retrieve primitive data types in key-value pairs. The data saved using SharedPreferences will be available even after your application is killed. This capability makes SharedPreferences suitable in different situations when user settings needs to be saved for example, or store data that can be used in different activities.
The data types that can be saved are booleans, floats, ints, longs, and strings.

To get an instance of SharedPreferences use the getSharedPreferences(String, int) method. The method takes 2 parameters: the name of the preference settings and the mode. (0 or MODE_PRIVATE for the default operation, MODE_WORLD_READABLE and MODE_WORLD_WRITEABLE to control permissions)

To write values:

  1. Call edit() to get a SharedPreferences.Editor instance
  2. Add values with methods such as putInt() and putString().
  3. Call commit() to save values.

To read values use such methods as getString() and getInt() of SharedPreferences instance.

Here’s a simple usage of SharedPreferences class:


public class SharedPrefsActivity extends Activity {

  public static final String PREFS_NAME = "MyApp_Settings";

  @Override
  public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);

     SharedPreferences settings = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);

     // Writing data to SharedPreferences
     Editor editor = settings.edit();
     editor.putString("key", "some value");
     editor.commit();

     // Reading from SharedPreferences
     String value = settings.getString("key", "");
     Log.d(TAG, value);
  }
}

Please visit the Android Tutorials page for more tutorials.

Creating a Preference Activity in Android

In this tutorial we will build a preference screen using the PreferenceActivity class. Our main activity will contain 2 Buttons and a TextView. One of the buttons will open the preference screen, and the other will display the values stored in SharedPreferences.

The final output should look like this:

 

And here’s what happens when clicking on the Username/Password fields (left screenshot), and the List Preference field (right screenshot):

 

At a first glance it may look a bit intimidating, but as you will see later, actually it’s quite easy to define a preference screen. Trust me, I’m an engineer! (c) 🙂

To put all this things together in a fashionable way, we will be using the PreferenceActivity class. The good thing about this class is that the definition of layout file it’s very simple. It provides custom controls specially designed for preference screens. Another good thing is that you don’t need to write code to save the values from preference screen to SharedPreferences. All this work is done automatically by the activity.

 

So, lets begin creating our preference screen

1. Create a new project in Eclipse:
Project: PreferenceDemoTest
Activity: PreferenceDemoActivity

2. Create a new Android XML file prefs.xml in the folder res/xml/. This file will contain the layout for our preference screen:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
 <PreferenceCategory
   android:summary="Username and password information"
   android:title="Login information" >
  <EditTextPreference
     android:key="username"
     android:summary="Please enter your login username"
     android:title="Username" />
  <EditTextPreference
     android:key="password"
     android:summary="Enter your password"
     android:title="Password" />
 </PreferenceCategory>

 <PreferenceCategory
   android:summary="Username and password information"
   android:title="Settings" >
  <CheckBoxPreference
     android:key="checkBox"
     android:summary="On/Off"
     android:title="Keep me logged in" />

  <ListPreference
     android:entries="@array/listOptions"
     android:entryValues="@array/listValues"
     android:key="listpref"
     android:summary="List preference example"
     android:title="List preference" />
 </PreferenceCategory>
</PreferenceScreen>

Notice that the root element of prefs.xml is the <PreferenceScreen> element, and not a RelativeLayout or LinearLayout for example. When a PreferenceActivity points to this layout file, the <PreferenceScreen> is used as the root, and the contained preferences are shown.

<PreferenceCategory> – defines a preference category. In our example the preference screen is split in two categories: “Login Information” and “Settings”

<EditTextPreference> – defines a text field for storing text information.

<CheckBoxPreference> – defines a checkbox.

<ListPreference> – defines a list of elements. The list appears as group of radio buttons.

 

3. At this stage the prefs.xml might complain that the @array/listOptions and @array/listValues resources cannot be found.

To fix this create a new XML file array.xml in the folder res/values/. This file will contain the elements of the ListPreference.

<?xml version="1.0" encoding="utf-8"?>
 <resources>
   <string-array name="listOptions">
     <item>Option 1</item>
     <item>Option 2</item>
     <item>Option 3</item>
     </string-array>

   <string-array name="listValues">
     <item>1 is selected</item>
     <item>2 is selected</item>
     <item>3 is selected</item>
   </string-array>
 </resources>

The “listOptions” array defines the elements of the list, or with other words, the labels.

The “listValues” array defines the values of each element. These are the values that will be stored in the SharedPreferences. The number of list options and list values should match. The first list value is assinged to the first list option, the second value to the second option,… and so on.

 

4. Create a new class PrefsActivity.java that extends PreferenceActivity:


public class PrefsActivity extends PreferenceActivity{

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   addPreferencesFromResource(R.xml.prefs);
}
}

Notice that instead of the traditional setContentView(), we use here addPreferencesFromResource() method. This inflates our prefs.xml file and uses it as the Activity’s current layout.

 

5. Add the PrefsActivity.java to the AndroidManifest file:

<application
......./>
  <activity
    android:name=".PrefsActivity"
    android:theme="@android:style/Theme.Black.NoTitleBar" >
  </activity>
</application>

 

6. Now, to test our preference activity lets modify the main.xml layout file by adding 2 Buttons and 1 TextView. One of the buttons will open the preference screen, and the other will display the values stored in SharedPreferences.

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >

<Button
  android:id="@+id/btnPrefs"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Preferences Screen" />

<Button
  android:id="@+id/btnGetPreferences"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Display Shared Preferences" />

<TextView
  android:id="@+id/txtPrefs"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />

</LinearLayout>

 

7. Finally, modify the PreferenceDemoActivity to handle our logic implementation:

public class PreferenceDemoActivity extends Activity {
TextView textView;

@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);

   Button btnPrefs = (Button) findViewById(R.id.btnPrefs);
   Button btnGetPrefs = (Button) findViewById(R.id.btnGetPreferences);

   textView = (TextView) findViewById(R.id.txtPrefs);

   View.OnClickListener listener = new View.OnClickListener() {

   @Override
   public void onClick(View v) {
   switch (v.getId()) {
   case R.id.btnPrefs:
      Intent intent = new Intent(PreferenceDemoActivity.this,
      PrefsActivity.class);
      startActivity(intent);
      break;

   case R.id.btnGetPreferences:
      displaySharedPreferences();
      break;

   default:
     break;
   }
   }
   };

   btnPrefs.setOnClickListener(listener);
   btnGetPrefs.setOnClickListener(listener);
}

private void displaySharedPreferences() {
   SharedPreferences prefs = PreferenceManager
    .getDefaultSharedPreferences(PreferenceDemoActivity.this);

   String username = prefs.getString("username", "Default NickName");
   String passw = prefs.getString("password", "Default Password");
   boolean checkBox = prefs.getBoolean("checkBox", false);
   String listPrefs = prefs.getString("listpref", "Default list prefs");

   StringBuilder builder = new StringBuilder();
   builder.append("Username: " + username + "\n");
   builder.append("Password: " + passw + "\n");
   builder.append("Keep me logged in: " + String.valueOf(checkBox) + "\n");
   builder.append("List preference: " + listPrefs);

   textView.setText(builder.toString());
}
}

Here we attach 2 listeners for each button and display the values retrieved from  SharedPreferences in a TextView.

By this time you should compile and run successfully the application.