1. Trang chủ
  2. » Công Nghệ Thông Tin

Android SDK (phần 7) ppsx

50 405 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Creating Map-Based Activities
Trường học Unknown University
Chuyên ngành Android Development
Thể loại Lecture notes
Năm xuất bản Unknown
Thành phố Unknown City
Định dạng
Số trang 50
Dung lượng 2,21 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

LISTING 8-9: Using map projections Point myPoint = new Point; // To screen coordinates projection.toPixelsgeoPoint, myPoint; // To GeoPoint location coordinates projection.fromPixelsmyPo

Trang 1

// Update the map location.

Double geoLat = location.getLatitude()*1E6;

Double geoLng = location.getLongitude()*1E6;

GeoPoint point = new GeoPoint(geoLat.intValue(),

geoLng.intValue());

mapController.animateTo(point);

double lat = location.getLatitude();

double lng = location.getLongitude();

latLongString = "Lat:" + lat + "\nLong:" + lng;

double latitude = location.getLatitude();

double longitude = location.getLongitude();

Geocoder gc = new Geocoder(this, Locale.getDefault());

try {

List<Address> addresses = gc.getFromLocation(latitude, longitude, 1);

StringBuilder sb = new StringBuilder();

if (addresses.size() > 0) {

Address address = addresses.get(0);

for (int i = 0; i < address.getMaxAddressLineIndex(); i++)

Trang 2

addressString = sb.toString();

} catch (IOException e) {}

} else { latLongString = "No location found";

} myLocationText.setText("Your Current Position is:\n" +

latLongString + "\n" + addressString);

}

All code snippets in this example are part of the Chapter 8 Where Am I? project, available for download at Wrox.com.

Creating and Using Overlays

Overlays enable you to add annotations and click handling toMapViews Each Overlay lets you draw2D primitives, including text, lines, images, and shapes, directly onto a canvas, which is then overlaidonto a Map View

You can add several Overlays onto a single map All the Overlays assigned to a Map View are added

as layers, with newer layers potentially obscuring older ones User clicks are passed through the stackuntil they are either handled by an Overlay or registered as clicks on the Map View itself

Creating New Overlays

Each Overlay is a canvas with a transparent background that is layered onto a Map View and used tohandle map touch events

To add a new Overlay create a new class that extendsOverlay Override thedrawmethod to draw theannotations you want to add, and overrideonTapto react to user clicks (generally made when the usertaps an annotation added by this Overlay)

Listing 8-8 shows the framework for creating a new Overlay that can draw annotations and handleuser clicks

LISTING 8-8: Creating a new Overlay

Trang 3

// Return true if screen tap is handled by this overlay

TheProjectionclass lets you translate between latitude/longitude coordinates (stored asGeoPoints)and x/y screen pixel coordinates (stored asPoints)

A map’s Projection may change between subsequentcalls to draw, so it’s good practice to get a newinstance each time Get a Map View’s Projection by callinggetProjection

Projection projection = mapView.getProjection();

Use thefromPixelandtoPixelmethods to translate from GeoPoints to Points and vice versa

For performance reasons, you can best use thetoPixelProjection method by passing a Point object to

be populated (rather than relying on the return value), as shown in Listing 8-9

LISTING 8-9: Using map projections

Point myPoint = new Point();

// To screen coordinates

projection.toPixels(geoPoint, myPoint);

// To GeoPoint location coordinates

projection.fromPixels(myPoint.x, myPoint.y);

Drawing on the Overlay Canvas

You handle Canvas drawing for Overlays by overriding the Overlay’sdrawhandler

The passed-in Canvas is the surface on which you draw your annotations, using the same techniquesintroduced in Chapter 4 for creating custom user interfaces for Views The Canvas object includes themethods for drawing 2D primitives on your map (including lines, text, shapes, ellipses, images, etc.).UsePaintobjects to define the style and color

Listing 8-10 uses a Projection to draw text and an ellipse at a given location

LISTING 8-10: A simple Map Overlay

@Override

public void draw(Canvas canvas, MapView mapView, boolean shadow) {

Projection projection = mapView.getProjection();

Double lat = -31.960906*1E6;

continues

Trang 4

// Create and setup your paint brush

Paint paint = new Paint();

For more advanced drawing features see Chapter 11, where gradients, strokes, and

filters are introduced.

Handling Map Tap Events

To handle map taps (user clicks), override theonTapevent handler within the Overlay extension class.TheonTaphandler receives two parameters:

➤ AGeoPointthat contains the latitude/longitude of the map location tapped

➤ TheMapViewthat was tapped to trigger this event

When you are overridingonTap, the method should returntrueif it has handled a particular tap andfalseto let another Overlay handle it, as shown in Listing 8-11

LISTING 8-11: Handling map-tap events

@Override

public boolean onTap(GeoPoint point, MapView mapView) {

// Perform hit test to see if this overlay is handling the click

if ([ . perform hit test . ]) {

[ . execute on tap functionality . ]

return true;

Trang 5

// If not handled return false

return false;

}

Adding and Removing Overlays

EachMapViewcontains a list of Overlays currently displayed You can get a reference to this list bycallinggetOverlays, as shown in the following snippet:

List<Overlay> overlays = mapView.getOverlays();

Adding and removing items from the list is thread-safe and synchronized, so you can modify and querythe list safely You should still iterate over the list within a synchronization block synchronized on theList

To add an Overlay onto a Map View, create a new instance of the Overlay and add it to the list, asshown in the following snippet

List<Overlay> overlays = mapView.getOverlays();

MyOverlay myOverlay = new MyOverlay();

overlays.add(myOverlay);

mapView.postInvalidate();

The added Overlay will be displayed the next time the Map View is redrawn, so it’s usually a goodpractice to callpostInvalidateafter you modify the list to update the changes on the map display

Annotating ‘Where Am I?’

This final modification to ‘‘Where Am I?’’ creates and adds a new Overlay that displays a white circle

at the device’s current position

1. Start by creating a newMyPositionOverlayOverlay class in the Where Am I? project

Trang 6

return false;

} }

2. Create a new instance variable to store the current Location, and add setter and getter ods for it

3. Override thedrawmethod to add a small white circle at the current location

private final int mRadius = 5;

@Override

public void draw(Canvas canvas, MapView mapView, boolean shadow) {

Projection projection = mapView.getProjection();

if (shadow == false) { // Get the current location Double latitude = location.getLatitude()*1E6;

Double longitude = location.getLongitude()*1E6;

GeoPoint geoPoint;

geoPoint = new GeoPoint(latitude.intValue(),longitude.intValue());

// Convert the location to screen pixels Point point = new Point();

projection.toPixels(geoPoint, point);

RectF oval = new RectF(point.x - mRadius, point.y - mRadius,

point.x + mRadius, point.y + mRadius);

// Setup the paint Paint paint = new Paint();

// Draw the marker canvas.drawOval(oval, paint);

canvas.drawRoundRect(backRect, 5, 5, backPaint);

Trang 7

point.x + 2*mRadius, point.y, paint);

}

super.draw(canvas, mapView, shadow);

}

4. Now open theWhereAmIActivity class, and add theMyPositionOverlayto theMapView

Start by adding a new instance variable to store theMyPositionOverlay, then override

onCreateto create a new instance of the class, and add it to theMapView’s Overlay list

// Add the MyPositionOverlay

positionOverlay = new MyPositionOverlay();

List<Overlay> overlays = myMapView.getOverlays();

String provider = locationManager.getBestProvider(criteria, true);

Location location = locationManager.getLastKnownLocation(provider);

Trang 8

myLocationText = (TextView)findViewById(R.id.myLocationText);

String addressString = "No address found";

if (location != null) { // Update my location marker

positionOverlay.setLocation(location);

// Update the map location.

Double geoLat = location.getLatitude()*1E6;

Double geoLng = location.getLongitude()*1E6;

GeoPoint point = new GeoPoint(geoLat.intValue(),

geoLng.intValue());

mapController.animateTo(point);

double lat = location.getLatitude();

double lng = location.getLongitude();

latLongString = "Lat:" + lat + "\nLong:" + lng;

double latitude = location.getLatitude();

double longitude = location.getLongitude();

Geocoder gc = new Geocoder(this, Locale.getDefault());

try { List<Address> addresses = gc.getFromLocation(latitude,

longitude, 1);

StringBuilder sb = new StringBuilder();

if (addresses.size() > 0) { Address address = addresses.get(0);

for (int i = 0; i < address.getMaxAddressLineIndex(); i++) sb.append(address.getAddressLine(i)).append("\n");

sb.append(address.getLocality()).append("\n");

sb.append(address.getPostalCode()).append("\n");

sb.append(address.getCountryName());

} addressString = sb.toString();

} catch (IOException e) {}

} else { latLongString = "No location found";

} myLocationText.setText("Your Current Position is:\n" +

latLongString + "\n" + addressString);

}

All code snippets in this example are part of the Chapter 8 Where Am I? project, available for download at Wrox.com.

When run, your application will display your current device location with a white circle and supportingtext, as shown in Figure 8-6

Trang 9

It’s worth noting that this is not the preferred technique for displaying your current

location on a map This functionality is implemented natively by Android through

theMyLocationOverlayclass If you want to display and follow your current

location, you should consider using (or extending) this class, as shown in the next

section, instead of implementing it manually as shown here.

Introducing My Location Overlay

FIGURE 8-6

TheMyLocationOverlayclass is a special Overlay designed

to show your current location and orientation on aMapView

To use My Location Overlay you need to create a new

instance, passing in the application Context and target Map

View, and add it to theMapView’s Overlay list, as shown

You can use My Location Overlay to display both your

current location (represented as a flashing blue marker) and

your current orientation (shown as a compass on the map

display)

The following snippet shows how to enable both the

compass and marker; in this instance the Map View’s

MapControlleris also passed in, allowing the Overlay to

automatically scroll the map if the marker moves

offscreen

myLocationOverlay.enableCompass();

myLocationOverlay.enableMyLocation(mapView.getMapController());

Introducing Itemized Overlays and Overlay Items

OverlayItems are used to supply simple maker functionality to your Map Views via the

ItemizedOverlayclass

ItemizedOverlaysprovide a convenient shortcut for adding markers to a map, letting you assign

a marker image and associated text to a particular geographical position TheItemizedOverlayinstance handles the drawing, placement, click handling, focus control, and layout optimization ofeachOverlayItemmarker for you

Trang 10

To add anItemizedOverlaymarker layer to your map, start by creating a new class that extendsItemizedOverlay<OverlayItem>, as shown in Listing 8-12.

ItemizedOverlayis a generic class that lets you create extensions based on any

OverlayItem-derived subclass.

Within the constructor you need to call through to the superclass after defining the bounds for yourdefault marker You must then callpopulateto trigger the creation of eachOverlayItem;populatemust be called whenever the data used to create the items changes

Within the implementation, overridesizeto return the number of markers to display andcreateItem

to create a new item based on the index of each marker

LISTING 8-12: Creating a new Itemized Overlay

import android.graphics.drawable.Drawable;

import com.google.android.maps.GeoPoint;

import com.google.android.maps.ItemizedOverlay;

import com.google.android.maps.OverlayItem;

public class MyItemizedOverlay extends ItemizedOverlay<OverlayItem> {

public MyItemizedOverlay(Drawable defaultMarker) {

public int size() {

// Return the number of markers in the collection

return 1;

}

}

Trang 11

To add anItemizedOverlayimplementation to your map, create a new instance (passing in the able marker image to use for each marker) and add it to the map’s Overlay list.

Draw-List<Overlay> overlays = mapView.getOverlays();

MyItemizedOverlay markers = new

MyItemizedOverlay(r.getDrawable(R.drawable.marker));

overlays.add(markers);

Note that the map markers placed by the Itemized Overlay use state to indicate if

when a marker has been selected.

In Listing 8-12, the list of Overlay items is static and defined in code More typically your Overlay itemswill be a dynamic ArrayList to which you will want to add and remove items at run time

Listing 8-13 shows the skeleton class for a dynamic Itemized Overlay implementation, backed by anArrayList, and supporting the addition and removal of items at run time

LISTING 8-13: Skeleton code for a dynamic Itemized Overlay

public class MyDynamicItemizedOverlay extends ItemizedOverlay<OverlayItem>

{

private ArrayList<OverlayItem> items;

public MyDynamicItemizedOverlay(Drawable defaultMarker) {

Trang 12

Pinning Views to the Map and Map Positions

You can pin any View-derived object to a Map View (including layouts and other View Groups),attaching it to either a screen position or a geographical map location

In the latter case, the View will move to follow its pinned position on the map, effectively acting as aninteractive map marker As a more resource-intensive solution, this is usually reserved for supplying thedetail ‘‘balloons’’ often displayed on mashups to provide further detail when a marker is clicked.You implement both pinning mechanisms by callingaddViewon theMapView, usually from theonCreate

oronRestoremethods within theMapActivitycontaining it Pass in the View you want to pin and thelayout parameters to use

TheMapView.LayoutParamsparameters you pass in toaddViewdetermine how, and where, the View isadded to the map

To add a new View to the map relative to the screen, specify a newMapView.LayoutParams,includingarguments that set the height and width of the View, the x/y screen coordinates to pin to, and thealignment to use for positioning, as shown in Listing 8-14

LISTING 8-14: Pinning a View to a map

mapView.addView(editText1, screenLP);

To pin a View relative to a physical map location, pass four parameters when constructing the newMap ViewLayoutParams, representing the height, width, GeoPoint to pin to, and layout alignment asshown in Listing 8-15

LISTING 8-15: Pinning a View to a geographical location

Double lat = 37.422134*1E6;

Double lng = -122.084069*1E6;

Trang 13

MapView.LayoutParams geoLP;

geoLP = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT,

MapView.LayoutParams.WRAP_CONTENT, geoPoint,

MAPPING EARTHQUAKES EXAMPLE

The following step-by-step guide demonstrates how to build a map-based Activity for the Earthquakeproject you started in Chapter 5 The newMapActivitywill display a map of recent earthquakes usingtechniques you learned within this chapter

1. Create a new earthquake_map.xml layout resource that includes aMapView, being sure toinclude anandroid:idattribute and anandroid:apiKeyattribute that contains your AndroidMaps API key

Trang 14

public class EarthquakeMap extends MapActivity {

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.earthquake_map);

}

@Override protected boolean isRouteDisplayed() { return false;

} }

3. Update the application manifest to include your newEarthquakeMapActivity and import themap library

4. Add a new menu option to theEarthquakeActivity to display theEarthquakeMapActivity

4.1. Start by adding a new string to the strings.xml resource for the menu text

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

<string name="auto_update_prompt">Auto Update?</string>

<string name="update_freq_prompt">Update Frequency</string>

Trang 15

4.2. Then add a new menu identifier before modifying theonCreateOptionsMenu

han-dler to add the new Menu Item It should use the text defined in Step 4.1, and whenselected it should fire an Intent to explicitly start theEarthquakeMapActivity

static final private int MENU_EARTHQUAKE_MAP = Menu.FIRST+2;

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

Intent startMap = new Intent(this, EarthquakeMap.class);

menu.add(0, MENU_EARTHQUAKE_MAP,

Menu.NONE, R.string.menu_earthquake_map).setIntent(startMap);

public void draw(Canvas canvas, MapView mapView, boolean shadow) {

Projection projection = mapView.getProjection();

5.1. Add a new constructor that accepts aCursorto the current earthquake data, and

store that Cursor as an instance variable

Cursor earthquakes;

public EarthquakeOverlay(Cursor cursor, ContentResolver resolver) {

super();

earthquakes = cursor;

Trang 16

5.2. Create a newrefreshQuakeLocationsmethod that iterates over the results Cursor

and extracts the location of each earthquake, extracting the latitude and longitudebefore storing each coordinate in a List ofGeoPoints

ArrayList<GeoPoint> quakeLocations;

private void refreshQuakeLocations() {

if (earthquakes.moveToFirst())

do { Double lat = earthquakes.getFloat(EarthquakeProvider.LATITUDE_COLUMN) * 1E6; Double lng =

earthquakes.getFloat(EarthquakeProvider.LONGITUDE_COLUMN) * 1E6; GeoPoint geoPoint = new GeoPoint(lng.intValue(),

lat.intValue());

quakeLocations.add(geoPoint);

} while(earthquakes.moveToNext());

}

5.3. CallrefreshQuakeLocationsfrom the Overlay’s constructor Also register a

DataSetObserveron the results Cursor that refreshes the Earthquake Location list

if a change in the Earthquake Cursor is detected

public EarthquakeOverlay(Cursor cursor) { super();

} });

}

5.4. Complete theEarthquakeOverlayby overriding thedrawmethod to iterate over the

list ofGeoPoints, drawing a marker at each earthquake location In this example

a simple red circle is drawn, but you could easily modify it to include additionalinformation, such as by adjusting the size of each circle based on the magnitude ofthe quake

int rad = 5;

@Override public void draw(Canvas canvas, MapView mapView, boolean shadow) {

Projection projection = mapView.getProjection();

// Create and setup your paint brush Paint paint = new Paint();

paint.setARGB(250, 255, 0, 0);

paint.setAntiAlias(true);

paint.setFakeBoldText(true);

Trang 17

if (shadow == false) { for (GeoPoint point : quakeLocations) { Point myPoint = new Point();

}

6. Return to theEarthquakeMapclass Within theonCreatemethod, create a Cursor that

returns the earthquakes you want to display on the map Use this Cursor to create a newEarthquakeOverlaybefore adding the new instance to the Map View’s list of Overlays

MapView earthquakeMap = (MapView)findViewById(R.id.map_view);

EarthquakeOverlay eo = new EarthquakeOverlay(earthquakeCursor);

Trang 18

8. If you run the application and select Earthquake Map from the main menu, your applicationshould appear as shown in Figure 8-7.

All code snippets in this example are part of the Chapter 8 Earthquake project, available for download at Wrox.com.

SUMMARY

FIGURE 8-7

Location-based services, the Geocoder, and MapViews are

available to create intuitive, location-aware applications that

feature geographical information

This chapter introduced the Geocoder and showed how to

perform forward and reverse geocoding lookups to translate

between map coordinates and street addresses You were

introduced to location-based services, used to find the

cur-rent geographical position of a device You also used them

to track movement and create proximity alerts

Then you created interactive map applications Using

Over-lays and Views you annotatedMapViewswith 2D graphics,

as well as markers in the form ofOverlayItemsand Views

(including View Groups and layouts)

In Chapter 9 you’ll learn how to work from the background

You’ll be introduced to the Service component and learn

how to move processing onto background threads To

inter-act with the user while hidden from view, you’ll use Toasts

to display transient messages and the Notification Manager

to ring, vibrate, and flash the phone

Trang 19

Working in the Background

WHAT’S IN THIS CHAPTER?

➤ Creating, starting, and stopping Services

➤ Binding Services to Activities

➤ Setting Service priority to foreground

➤ Using AsyncTasks to manage background processing

➤ Creating background threads and using Handlers to synchronize with

the GUI thread

➤ Displaying Toasts

➤ Using the Notification Manager to notify users of application events

➤ Creating insistent and ongoing Notifications

➤ Using Alarms to schedule application events

Android offers theServiceclass to create application components specifically to handle tions and functionality that should run invisibly, without a user interface

opera-Android accords Services a higher priority than inactive Activities, so they’re less likely to bekilled when the system requires resources In fact, should the run time prematurely terminate aService that’s been started, it can be configured to restart as soon as sufficient resources becomeavailable In extreme cases, the termination of a Service — such as an interruption in musicplayback — will noticeably affect the user experience, and in these cases a Service’s priority can

be raised to the equivalent of a foreground Activity

By using Services, you can ensure that your applications continue to run and respond to events,even when they’re not in active use

Services run without a dedicated GUI, but, like Activities and Broadcast Receivers, they still cute in the main thread of the application’s process To help keep your applications responsive,

Trang 20

exe-you’ll learn to move time-consuming processes (like network lookups) into background threads usingtheThreadandAsyncTaskclasses.

Android offers several techniques for applications to communicate with users without an Activity.You’ll learn how to use Notifications and Toasts to alert and update users without interrupting theactive application

Toasts are a transient, non-modal dialog-box mechanism used to display information to users

with-out stealing focus from the active application You’ll learn to display Toasts from any applicationcomponent to send unobtrusive on-screen messages to your users

Where Toasts are silent and transient, Notifications represent a more robust mechanism for alerting

users In many cases, when the user isn’t actively using the mobile phone it sits silent and unwatched in

a pocket or on a desk until it rings, vibrates, or flashes Should a user miss these alerts, status bar iconsare used to indicate that an event has occurred All these attention-grabbing antics are available to yourAndroid application through Notifications

Alarms provide a mechanism for firing Intents at set times, outside the control of your application lifecycle You’ll learn to use Alarms to start Services, open Activities, or broadcast Intents based on eitherthe clock time or the time elapsed since device boot An Alarm will fire even after its owner applicationhas been closed, and can (if required) wake a device from sleep

INTRODUCING SERVICES

Unlike Activities, which present a rich graphical interface to users, Services run in the background —updating your Content Providers, firing Intents, and triggering Notifications They are the perfectmeans of performing ongoing or regular processing and of handling events even when your applica-tion’s Activities are invisible or inactive, or have been closed

Services are started, stopped, and controlled from other application components, including otherServices, Activities, and Broadcast Receivers If your application performs actions that don’t dependdirectly on user input, Services may be the answer

Started Services always have higher priority than inactive or invisible Activities, making them less likely

to be terminated by the run time’s resource management The only reason Android will stop a Serviceprematurely is to provide additional resources for a foreground component (usually an Activity) Whenthat happens, your Service will be restarted automatically when resources become available

If your Service is interacting directly with the user (for example, by playing music) it may be necessary toincrease its priority to that of a foreground Activity This will ensure that your Service isn’t terminatedexcept in extreme circumstances, but reduces the run time’s ability to manage its resources, potentiallydegrading the overall user experience

Applications that update regularly but only rarely or intermittently need user interaction are goodcandidates for implementation as Services MP3 players and sports-score monitors are examples ofapplications that should continue to run and update without a visible Activity

Further examples can be found within the software stack itself: Android implements several Services,including the Location Manager, Media Controller, and Notification Manager

Trang 21

Creating and Controlling Services

In the following sections you’ll learn how to create a new Service, and how to start and stop it usingIntents and thestartServicemethod Later you’ll learn how to bind a Service to an Activity to provide

a richer communications interface

public void onCreate() {

// TODO: Actions to perform when service is created.

}

@Override

public IBinder onBind(Intent intent) {

// TODO: Replace with service binding implementation.

TheonStartCommandhandler replaces theonStartevent that was used prior to Android 2.0 By trast, it enables you to tell the system how to handle restarts if the Service is killed by the system prior

con-to an explicit call con-tostopServiceorstopSelf

The following snippet extends Listing 9-1 to show the skeleton code for overriding theonStartCommandhandler Note that it returns a value that controls how the system will respond if the Service is restartedafter being killed by the run time

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

// TODO Launch a background thread to do processing.

return Service.START_STICKY;

}

Services are launched on the main Application thread, meaning that any processing done in theonStartCommandhandler will happen on the main GUI thread The standard pattern for implementing

Trang 22

a Service is to create and run a new thread fromonStartCommandto perform the processing in thebackground and stop the Service when it’s complete (you will be shown how to create and managebackground threads later in this chapter).

This pattern letsonStartCommandcomplete quickly, and lets you control the restart behavior using one

of the followingServiceconstants:

➤ START_STICKY Describes the standard behavior, which is similar to the way in whichonStartwas implemented prior to Android 2.0 If you return this value,onStartCommandwill

be called any time your Service restarts after being terminated by the run time Note that on arestart the Intent parameter passed in toonStartCommandwill benull

This mode is typically used for Services that handle their own states, and that are explicitlystarted and stopped as required (viastartServiceandstopService) This includes Servicesthat play music or handle other ongoing background tasks

➤ START_NOT_STICKY This mode is used for Services that are started to process specific actions

or commands Typically they will usestopSelfto terminate once that command has beencompleted

Following termination by the run time, Services set to this mode will restart only if there arepending start calls If nostartServicecalls have been made since the Service was terminated,the Service will be stopped without a call being made toonStartCommand

This mode is ideal for Services that handle specific requests, particularly regular processingsuch as updates or network polling Rather than restarting the Service during a period ofresource contention, it’s often more prudent tolet the Service stop and retry at the next sched-uled interval

➤ START_REDELIVER_INTENT In some circumstances you will want to ensure that the mands you have requested from your Service are completed

com-This mode is a combination of the first two — if the Service is terminated by the run time, it

will restart only if there are pending start calls or the process was killed prior to its calling

event handler to let you perform actions when the Service started Implementing

theonStarthandler is now the equivalent of overridingonStartCommandand

The restart mode you specify in youronStartCommandreturn value will affect the parameter valuespassed in to subsequent calls

Trang 23

Initially the Intent will be the parameter you passed in tostartServiceto start your Service Aftersystem-based restarts it will be either null, in the case ofSTART_STICKYmode, or the original Intent, ifthe mode is set toSTART_REDELIVER_INTENT.

Theflagparameter can be used to discover how the Service was started In particular you can use thecode snippet shown in Listing 9-2 to determine if either of the following cases is true:

➤ START_FLAG_REDELIVERY Indicates that the Intent parameter is a redelivery caused by thesystem run time’s having terminated the Service before it was explicitly stopped by a call tostopSelf

➤ START_FLAG_RETRY Indicates that the Service has been restarted after an abnormal tion Passed in when the Service was previously set toSTART_STICKY

termina-LISTING 9-2: Determining the cause of a system start

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

if ((flags & START_FLAG_RETRY) == 0) {

// TODO If it’s a restart, do something.

Registering a Service in the Manifest

Once you’ve constructed a new Service, you have to register it in the application manifest

Do this by including a<service>tag within theapplicationnode Use therequires-permissionattribute to require a uses-permission for other applications to access this Service

The following is theservicetag you’d add for the skeleton Service you created earlier:

<service android:enabled="true" android:name=".MyService"/>

Self-Terminating a Service

Once your Service has completed the actions or processing it was started for, you should make a call

tostopSelf, either without a parameter to force a stop, or by passing in astartIdvalue to insure cessing has been completed for each instance ofstartServicecalled so far, as shown in the followingsnippet:

pro-stopSelf(startId);

By explicitly stopping the Service when your processing is complete, you allow the system to recoverthe resources otherwise required to keep it running Due to the high priority of Services they are notcommonly killed by the run time, so self-termination can significantly improve the resource footprint

of your application

Trang 24

Starting, Controlling, and Interacting with a Service

To start a Service, callstartService; you can either use an action to implicitly start a Service with theappropriate Intent Receiver registered, or you can explicitly specify the Service using its class If theService requires permissions that your application does not have, the call tostartServicewill throw aSecurityException

In both cases you can pass values in to the Service’sonStarthandler by adding extras to the Intent, asshown in Listing 9-3, which demonstrates both techniques available for starting a Service

LISTING 9-3: Starting a Service

// Implicitly start a Service

Intent myIntent = new Intent(MyService.ORDER_PIZZA);

myIntent.putExtra("TOPPING", "Margherita");

startService(myIntent);

// Explicitly start a Service

startService(new Intent(this, MyService.class));

MyServiceclass and use an Intent Filter to register the Service as a provider of

MY_ACTION.

To stop a Service usestopService, passing an Intent that defines the Service to stop Listing 9-4 firststarts and then stops a Service both explicitly and by using the component name returned from a call

tostartService

LISTING 9-4: Stopping a Service

ComponentName service = startService(new Intent(this, BaseballWatch.class));

// Stop a service using the service name.

stopService(new Intent(this, service.getClass()));

// Stop a service explicitly.

try {

Class serviceClass = Class.forName(service.getClassName());

stopService(new Intent(this, serviceClass));

} catch (ClassNotFoundException e) {}

IfstartServiceis called on a Service that’s already running, the Service’sonStartCommandhandler will

be executed again Calls tostartServicedo not nest, so a single call tostopServicewill terminate it

no matter how many timesstartServicehas been called

An Earthquake Monitoring Service Example

In this chapter you’ll modify the Earthquake example you started in Chapter 5 (and continued toenhance in Chapters 6, 7, and 8) In this example you’ll move the earthquake updating and processingfunctionality into a separate Service component

Trang 25

Later in this chapter you’ll build additional functionality within this Service,

starting by moving the network lookup and XML parsing to a background thread.

Later you’ll use Toasts and Notifications to alert users of new earthquakes.

1. Start by creating a newEarthquakeServicethat extendsService

public void onCreate() {

// TODO: Initialize variables, get references to GUI objects

<service android:enabled="true" android:name=".EarthquakeService"/>

3. Move therefreshEarthquakesandaddNewQuakemethods out of theEarthquakeActivityand into theEarthquakeService

You’ll need to remove the calls toaddQuakeToArrayandloadQuakesFromProvider(leaveboth of these methods in the Earthquake Activity because they’re still required) In the

EarthquakeServicealso remove all references to the earthquakes ArrayList

private void addNewQuake(Quake _quake) {

ContentResolver cr = getContentResolver();

// Construct a where clause to make sure we don’t already have

// this earthquake in the provider.

Ngày đăng: 05/07/2014, 15:20

TỪ KHÓA LIÊN QUAN