Login     Sign Up
Cyril Sermon (@admin)
10 months ago
57 Views

In Chapter 5, you created an earthquake monitor that showed a list of recent earthquakes based on an Internet feed.

In the following example, you’ll create a Preferences page for this earthquake viewer that lets users configure application settings for a more personalized experience. You’ll provide the option to toggle automatic updates, control the frequency of updates, and filter the minimum earthquake magnitude displayed.

Later in this chapter, you’ll extend this example further by creating a Content Provider to save and share earthquake data with other applications.

Open the Earthquake project you created in Chapter 5.

Add new String resources for the labels displayed in the “Preferences” screen. Also, add a String for the new Menu Item that will let users access the Preferences screen.

<?xml version=”1.0” encoding=”utf-8”?>

<resources>

<string name=”app_name”>Earthquake</string>

<string name=”quake_feed”>

http://earthquake.usgs.gov/eqcenter/catalogs/1day-M2.5.xml </string>

<string name=”menu_update”>Refresh Earthquakes</string>

<string name=”auto_update_prompt”>Auto Update?</string> <string name=”update_freq_prompt”>Update Frequency</string>

<string name=”min_quake_mag_prompt”>Minimum Quake Magnitude</string> <string name=”menu_preferences”>Preferences</string>

</resources>

Create a new preferences.xml layout resource that lays out the UI for the Preferences Activ-ity. Include a checkbox for indicating the “automatic update” toggle, and spinners to select the update rate and magnitude filter.

<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/auto_update_prompt”

/>

<CheckBox android:id=”@+id/checkbox_auto_update” android:layout_width=”fill_parent” android:layout_height=”wrap_content”

/>

<TextView

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:text=”@string/update_freq_prompt”

/>

<Spinner

android:id=”@+id/spinner_update_freq”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:drawSelectorOnTop=”true”

/>

<TextView

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:text=”@string/min_quake_mag_prompt”

/>

<Spinner

android:id=”@+id/spinner_quake_mag”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”

android:drawSelectorOnTop=”true”

/>

<LinearLayout

android:orientation=”horizontal”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content”>

<Button android:id=”@+id/okButton”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@android:string/ok”

/>

<Button

android:id=”@+id/cancelButton”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@android:string/cancel”

/>

</LinearLayout>

</LinearLayout>

Create four new array resources in a new res/values/arrays.xml file. They will provide the values to use for the update frequency and minimum magnitude filter.

<?xml version=”1.0” encoding=”utf-8”?>

<resources>

<string-array name=”update_freq_options”>

<item>Every Minute</item>

<item>5 minutes</item>

<item>10 minutes</item>

<item>15 minutes</item>

<item>Every Hour</item>

</string-array>

<array name=”magnitude”>

<item>3</item>

<item>5</item>

<item>6</item>

<item>7</item>

<item>8</item>

</array>

<string-array name=”magnitude_options”>

<item>3</item>

<item>5</item>

<item>6</item>

<item>7</item>

<item>8</item>

</string-array>

<array name=”update_freq_values”>

<item>1</item>

<item>5</item>

<item>10</item>

<item>15</item>

<item>60</item>

</array>

</resources>

Create the Preferences Activity. It will be used to display the application preferences.

Override onCreate to inflate the layout you created in Step 2, and get references to the Checkbox and both Spinner controls. Then make a call to the populateSpinners stub.

package com.paad.earthquake;

import android.app.Activity;

import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.view.View;

import android.widget.ArrayAdapter;

import android.widget.Button;

import android.widget.CheckBox;

import android.widget.Spinner;

public class Preferences extends Activity {

CheckBox autoUpdate;

Spinner updateFreqSpinner;

Spinner magnitudeSpinner;

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.preferences);

updateFreqSpinner =

(Spinner)findViewById(R.id.spinner_update_freq); magnitudeSpinner = (Spinner)findViewById(R.id.spinner_quake_mag); autoUpdate = (CheckBox)findViewById(R.id.checkbox_auto_update);

populateSpinners();

}

private void populateSpinners() {

}

}

Fill in the populateSpinners method, using Array Adapters to bind each Spinner to its corre-sponding array.

private void populateSpinners() {

Populate the update frequency spinner ArrayAdapter<CharSequence> fAdapter;

fAdapter = ArrayAdapter.createFromResource(this,

R.array.update_freq_options,

android.R.layout.simple_spinner_item); fAdapter.setDropDownViewResource(

android.R.layout.simple_spinner_dropdown_item);

updateFreqSpinner.setAdapter(fAdapter);

Populate the minimum magnitude spinner ArrayAdapter<CharSequence> mAdapter;

mAdapter = ArrayAdapter.createFromResource(this,

R.array.magnitude_options,

android.R.layout.simple_spinner_item);

mAdapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item);

magnitudeSpinner.setAdapter(mAdapter);

}

updateFreqSpinner.setAdapter(fAdapter);

Populate the minimum magnitude spinner ArrayAdapter<CharSequence> mAdapter;

mAdapter = ArrayAdapter.createFromResource(this,

R.array.magnitude_options,

android.R.layout.simple_spinner_item);

mAdapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item);

magnitudeSpinner.setAdapter(mAdapter);

}

Add public static String values to use to identify the named Shared Preference you’re going to cre-ate, and the keys it will use to store each preference value. Update the onCreate method to retrieve the named preference and call updateUIFromPreferences. The updateUIFromPreferences method uses the get<type> methods on the Shared Preference object to retrieve each preference value and apply it to the current UI.

public static final String USER_PREFERENCE = “USER_PREFERENCES”;

public static final String PREF_AUTO_UPDATE = “PREF_AUTO_UPDATE”;

public static final String PREF_MIN_MAG = “PREF_MIN_MAG”;

public static final String PREF_UPDATE_FREQ = “PREF_UPDATE_FREQ”;

SharedPreferences prefs;

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.preferences);

updateFreqSpinner = (Spinner)findViewById(R.id.spinner_update_freq); magnitudeSpinner = (Spinner)findViewById(R.id.spinner_quake_mag); autoUpdate = (CheckBox)findViewById(R.id.checkbox_auto_update);

populateSpinners();

prefs = getSharedPreferences(USER_PREFERENCE, Activity.MODE_PRIVATE); updateUIFromPreferences();

}

private void updateUIFromPreferences() {

boolean autoUpChecked = prefs.getBoolean(PREF_AUTO_UPDATE, false); int updateFreqIndex = prefs.getInt(PREF_UPDATE_FREQ, 2); int minMagIndex = prefs.getInt(PREF_MIN_MAG, 0);

updateFreqSpinner.setSelection(updateFreqIndex); magnitudeSpinner.setSelection(minMagIndex); autoUpdate.setChecked(autoUpChecked);

}

Still in the onCreate method, add event handlers for the OK and Cancel buttons. Cancel should close the Activity, while OK should call savePreferences first.

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.preferences);

updateFreqSpinner = (Spinner)findViewById(R.id.spinner_update_freq); magnitudeSpinner = (Spinner)findViewById(R.id.spinner_quake_mag); autoUpdate = (CheckBox)findViewById(R.id.checkbox_auto_update);

populateSpinners();

prefs = getSharedPreferences(USER_PREFERENCE, Activity.MODE_PRIVATE); updateUIFromPreferences();

Button okButton = (Button) findViewById(R.id.okButton); okButton.setOnClickListener(new View.OnClickListener() {

public void onClick(View view) {

savePreferences();

Preferences.this.setResult(RESULT_OK);

finish();

}

});

Button cancelButton = (Button) findViewById(R.id.cancelButton); cancelButton.setOnClickListener(new View.OnClickListener() {

public void onClick(View view) { Preferences.this.setResult(RESULT_CANCELED); finish();

}

});

}

private void savePreferences() {

}

Fill in the savePreferences method to record the current preferences, based on the UI selec-tions, to the Shared Preference object.

private void savePreferences() {

int updateIndex = updateFreqSpinner.getSelectedItemPosition(); int minMagIndex = magnitudeSpinner.getSelectedItemPosition(); boolean autoUpdateChecked = autoUpdate.isChecked();

Editor editor = prefs.edit();

editor.putBoolean(PREF_AUTO_UPDATE, autoUpdateChecked); editor.putInt(PREF_UPDATE_FREQ, updateIndex); editor.putInt(PREF_MIN_MAG, minMagIndex); editor.commit();

}

That completes the Preferences Activity. Make it accessible in the application by adding it to the application manifest.

<activity android:name=”.Preferences” android:label=”Earthquake Preferences”>

</activity>

Now return to the Earthquake Activity, and add support for the new Shared Preferences file and a Menu Item to display the Preferences Activity.

Start by adding the new Menu Item. Extend the onCreateOptionsMenu method to include a new item that opens the Preferences Activity.

static final private int MENU_PREFERENCES = Menu.FIRST+1;

@Override

public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu);

menu.add(0, MENU_UPDATE, Menu.NONE, R.string.menu_update); menu.add(0, MENU_PREFERENCES, Menu.NONE, R.string.menu_preferences);

return true;

}

Modify the onOptionsItemSelected method to display the Preferences Activity when the new Menu Item is selected. Create an explicit Intent, and pass it in to the startActivityForResult method. This will launch the Preferences screen and alert the Earthquake class when the prefer-ences are saved through the onActivityResult handler.

private static final int SHOW_PREFERENCES = 1;

public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item);

switch (item.getItemId()) {

case (MENU_UPDATE): {

refreshEarthquakes();

return true;

}

case (MENU_PREFERENCES): {

Intent i = new Intent(this, Preferences.class); startActivityForResult(i, SHOW_PREFERENCES); return true;

}

}

return false;

}

Launch your application, and select Preferences from the Activity menu. The Preferences Activ-ity should be displayed as shown in Figure 6-1.

Figure 6-1

All that’s left is to apply the preferences to the Earthquake functionality.

Implementing the automatic updates will be left until Chapter 8, when you’ll learn how to use Services and background threads. For now, you can put the framework in place and apply the magnitude filter.

Start by creating a new updateFromPreferences method that reads the Shared Preference val-ues and creates instance variables for each of them.

int minimumMagnitude = 0;

boolean autoUpdate = false;

int updateFreq = 0;

private void updateFromPreferences() {

SharedPreferences prefs =

getSharedPreferences(Preferences.USER_PREFERENCE, Activity.MODE_PRIVATE);

int minMagIndex = prefs.getInt(Preferences.PREF_MIN_MAG, 0); if (minMagIndex < 0)

minMagIndex = 0;

int freqIndex = prefs.getInt(Preferences.PREF_UPDATE_FREQ, 0); if (freqIndex < 0)

freqIndex = 0;

autoUpdate = prefs.getBoolean(Preferences.PREF_AUTO_UPDATE, false);

Resources r = getResources();

// Get the option values from the arrays.

int[] minMagValues = r.getIntArray(R.array.magnitude);

int[] freqValues = r.getIntArray(R.array.update_freq_values);

Convert the values to ints. minimumMagnitude = minMagValues[minMagIndex]; updateFreq = freqValues[freqIndex];

}

Apply the magnitude filter by updating the addNewQuake method to check a new earthquake’s magnitude before adding it to the list.

private void addNewQuake(Quake _quake) {

if (_quake.getMagnitude() > minimumMagnitude) {

Add the new quake to our list of earthquakes. earthquakes.add(_quake);

Notify the array adapter of a change. aa.notifyDataSetChanged();

}

}

Override the onActivityResult handler to call updateFromPreferences and refresh the earthquakes whenever the Preferences Activity saves changes.

@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == SHOW_PREFERENCES)

if (resultCode == Activity.RESULT_OK) {

updateFromPreferences();

refreshEarthquakes();

}

}

Finally, call updateFromPreferences in onCreate (before the call to refreshEarthquakes) to ensure that the preferences are applied when the Activity first starts.

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

earthquakeListView =

(ListView)this.findViewById(R.id.earthquakeListView);

earthquakeListView.setOnItemClickListener(new OnItemClickListener() {

public void onItemClick(AdapterView _av, View _v, int _index, long arg3) {

selectedQuake = earthquakes.get(_index);

showDialog(QUAKE_DIALOG);

}

});

int layoutID = android.R.layout.simple_list_item_1;

= new ArrayAdapter<Quake>(this, layoutID, earthquakes); earthquakeListView.setAdapter(aa);

updateFromPreferences();

refreshEarthquakes();

}