Esta entrada completa la explicación del ejemplo tratado en la serie de entradas Un ejemplo de aplicación Java para BlackBerry. Ver enlaces al final.

Recapitulando

GPSDemo es una aplicación para BlackBerry que hace uso de la API JSR-179 para mostrar información de la posición y velocidad obtenidas de un dispositivo GPS o similar (ver la entrada Leyendo nuestro GPS desde Java con la JavaME Location API (JSR-179) – Parte I para una explicación de las posibles fuentes de información).

Habíamos dejado pendiente de describir el método startLocationUpdate() que se llama desde el constructor de la clase GPSDemo:

private void startLocationUpdate()<br /> {<br /> try<br /> {<br /> _locationProvider = LocationProvider.getInstance(null);<br /> if ( _locationProvider == null )<br /> {<br /> Dialog.alert("GPS is not supported on this platform, exiting...");<br /> System.exit(0);<br /> }<br /> _locationProvider.setLocationListener(new LocationListenerImpl(), _interval, 1, 1);<br /> }<br /> catch (LocationException le)<br /> {<br /> System.err.println("Failed to add a location listener. Exiting...");<br /> System.err.println(le);<br /> System.exit(0);<br /> }<br /> }

Lo primero que hacemos es obtener un proveedor de contenidos, con los criterios por defecto. En caso de no poder obtener uno, salimos de la aplicación.

La otra cosa que hace este método es establecer el objeto responsable de escuchar la información que llega del GPS. La variable internal se estableció previamente al valor 1, con lo que la información se actualizará aproxamadamente una vez por segundo. Los dos últimos parámetros establecen el _timeout y la caducidad de los datos.

Para actuar como listener del GPS una clase debe implementar la interfaz LocationListener.

La clase LocationListenerImpl

De forma más bien descriptiva, la clase listener de nuestro ejemplo se llama LocationListenerImpl:

private class LocationListenerImpl implements LocationListener<br /> {<br /> // Members. --------------------------------------------------------------<br /> private int captureCount;

public void providerStateChanged(LocationProvider provider, int newState)<br /> {<br /> // No operation defined.<br /> }<br /> ...

La interfaz tiene dos métodos. providerStateChanged nos avisa de los cambios de estado de nuestro proveedor de localización, básicamente cuando deja de estar disponible por algún tipo de problema; como estamos pensando sólo en el GPS, que no va a quedar fuera de servicio, no implementamos este método.

El otro método es el que nos avisa de que el GPS ha suministrado una nueva localización:

public void locationUpdated(LocationProvider provider, Location location)<br /> {<br /> if(location.isValid())<br /> {<br /> float heading = location.getCourse();<br /> double longitude = location.getQualifiedCoordinates().getLongitude();<br /> double latitude = location.getQualifiedCoordinates().getLatitude();<br /> float altitude = location.getQualifiedCoordinates().getAltitude();<br /> float speed = location.getSpeed();<br /> // Horizontal distance.<br /> float horizontalDistance = speed * _interval;<br /> _horizontalDistance += horizontalDistance;<br /> // Horizontal distance for this waypoint.<br /> _wayHorizontalDistance += horizontalDistance;<br /> // Distance over the current interval.<br /> float totalDist = 0;<br /> // Moving average grade.<br /> for(int i = 0; i 0) _verticalDistance = _verticalDistance + altGain;<br /> captureCount += _interval;<br /> // If we’re mod zero then it’s time to record this data.<br /> captureCount %= CAPTURE_INTERVAL;<br /> // Information to display on the device.<br /> StringBuffer sb = new StringBuffer();<br /> sb.append("Longitude: " + longitude+ "\n");<br /> sb.append("Latitude: " + latitude+ "\n");<br /> sb.append("Altitude: " + altitude + " m\n");<br /> sb.append("Heading relative to true north: " + heading + "\n");<br /> sb.append("Speed : " + speed + +" m/s\n");<br /> sb.append("Grade : ");<br /> if(Float.isNaN(grade))<br /> sb.append(" Not available");<br /> else<br /> sb.append(grade+" %");<br /> GPSDemo.this.updateLocationScreen(sb.toString());<br /> }<br /> }

Mucho código, pero muy simple. Se nos pasa como parámetros el LocationProvider, que no necesitamos, y un objeto Location que contiene, además de las coordenadas, la velocidad, la dirección y un método (isValid()) que nos dice si el objeto Location tiene coordenadas o no. En caso de utilizar como proveedor de contenidos un servicio de pago del operador, podríamos tener información adicional en el mismo objeto, como una dirección postal.

Código de GPSDemo.java

`/**

  • A GPS sample application using the JSR 179 APIs.
    *
  • Copyright (C) 2005 Research In Motion Limited.
    /
    package com.rim.samples.docs.gpsdemo;
    import net.rim.device.api.ui.
    ;
    import net.rim.device.api.ui.component.;
    import net.rim.device.api.ui.container.
    ;
    import com.rim.samples.docs.baseapp.;
    import net.rim.device.api.io.
    ;
    import net.rim.device.api.system.;
    import net.rim.device.api.i18n.
    ;
    import javax.microedition.io.;
    import java.util.
    ;
    import java.io.;
    import javax.microedition.location.
    ;
    import net.rim.device.api.util.;
    import com.rim.samples.docs.resource.
    ;
    /* This application acts as a simple travel computer, recording route coordinates,
  • speed, and altitude.
  • Recording begins as soon as the application is invoked.
    /
    public class GPSDemo extends BaseApp implements GPSDemoResResource
    {
    // Constants. —————————————————————-
    // The number of updates in seconds over which the altitude is calculated.
    private static final int GRADE_INTERVAL=5;
    // com.rim.samples.docs.gpsdemo.GPSDemo.ID
    private static final long ID = 0x4e94d9bc9c54fed3L;
    private static final int CAPTURE_INTERVAL=10;
    // Statics. ——————————————————————
    private static ResourceBundle _resources =
    ResourceBundle.getBundle(GPSDemoResResource.BUNDLE_ID, GPSDemoResResource.BUNDLE_NAME);
    // The period of the position query in seconds.
    private static int _interval = 1;
    private static Vector _previousPoints;
    private static float[] _altitudes;
    private static float[] _horizontalDistances;
    private static PersistentObject _store;
    // Initialize or reload the persistent store.
    static
    {
    _store = PersistentStore.getPersistentObject(ID);
    if(_store.getContents()==null)
    {
    _previousPoints= new Vector();
    _store.setContents(_previousPoints);
    }
    _previousPoints=(Vector)_store.getContents();
    }
    private long _startTime;
    private float _wayHorizontalDistance;
    private float _horizontalDistance;
    private float _verticalDistance;
    private ListField _listField;
    private EditField _status;
    private StringBuffer _messageString;
    private String _oldmessageString;
    private LocationProvider _locationProvider;
    /
    Instantiate the new application object and enter the event loop.
  • @param args unsupported. no args are supported for this application
    /
    public static void main(String[] args)
    {
    new GPSDemo().enterEventDispatcher();
    }
    // Constructors. ————————————————————-
    public GPSDemo()
    {
    // Used by waypoints; represents the time since the last waypoint.
    _startTime = System.currentTimeMillis();
    _altitudes=new float[GRADE_INTERVAL];
    _horizontalDistances=new float[GRADE_INTERVAL];
    _messageString= new StringBuffer();
    MainScreen screen = new MainScreen();
    screen.setTitle(new LabelField(_resources.getString(GPSDEMO_TITLE), LabelField.USE_ALL_WIDTH));
    _status = new EditField();
    screen.add(_status);
    screen.addKeyListener(this);
    screen.addTrackwheelListener(this);
    // Start the GPS thread that listens for updates.
    startLocationUpdate();
    // Render our screen.
    pushScreen(screen);
    }
    /
    Update the GUI with the data just received.
    /
    private void updateLocationScreen(final String msg)
    {
    invokeLater(new Runnable()
    {
    public void run()
    {
    _status.setText(msg);
    }
    });
    }
    // Menu items. —————————————————————
    // Cache the markwaypoint menu item for reuse.
    private MenuItem _markWayPoint = new MenuItem(_resources, GPSDEMO_MENUITEM_MARKWAYPOINT, 110, 10)
    {
    public void run()
    {
    GPSDemo.this.markPoint();
    }
    };
    // Cache the view waypoints menu item for reuse.
    private MenuItem _viewWayPoints = new MenuItem(_resources, GPSDEMO_MENUITEM_VIEWWAYPOINTS, 110, 10)
    {
    public void run()
    {
    GPSDemo.this.viewPreviousPoints();
    }
    };
    // Cache the close menu item for reuse.
    private MenuItem _close = new MenuItem(_resources, GPSDEMO_MENUITEM_CLOSE, 110, 10)
    {
    public void run()
    {
    System.exit(0);
    }
    };
    protected void makeMenu(Menu menu, int instance)
    {
    menu.add( _markWayPoint );
    menu.add( _viewWayPoints );
    menu.add( _close );
    menu.addSeparator();
    super.makeMenu(menu, instance);
    }
    /
    Invokes the Location API with the default criteria.
    /
    private void startLocationUpdate()
    {
    try
    {
    _locationProvider = LocationProvider.getInstance(null);
    if ( _locationProvider == null )
    {
    Dialog.alert(“GPS is not supported on this platform, exiting…”);
    System.exit(0);
    }
    // A single listener can be associated with a provider,
    // and unsetting it involves the same call but with null,
    // so there is no need to cache the listener instance.
    // Request an update every second.
    _locationProvider.setLocationListener(new LocationListenerImpl(), _interval, 1, 1);
    }
    catch (LocationException le)
    {
    System.err.println(“Failed to add a location listener. Exiting…”);
    System.err.println(le);
    System.exit(0);
    }
    }
    /
    Marks a point in the persistent store. Calculations are based on
  • all data collected since the previous way point, or from the start
  • of the application if no previous waypoints exist.
    /
    private void markPoint()
    {
    long current = System.currentTimeMillis();
    WayPoint p= new WayPoint(_startTime, current, _wayHorizontalDistance, _verticalDistance);
    addWayPoint(p);
    // Reset the waypoint variables.
    _startTime = current;
    _wayHorizontalDistance = 0;
    _verticalDistance = 0;
    }
    // View the saved waypoints.
    private void viewPreviousPoints()
    {
    PointScreen pointScreen = new PointScreen(_previousPoints, _resources);
    pushScreen(pointScreen);
    }
    // Called by the framework when this application is losing focus.
    protected void onExit()
    {
    if ( _locationProvider != null )
    {
    _locationProvider.reset();
    _locationProvider.setLocationListener(null, -1, -1, -1);
    }
    }
    /
    Adds a new WayPoint and commits the set of saved waypoints
  • to flash memory.
  • @param p The point to add.
    /
    /
    package/
    synchronized static void addWayPoint(WayPoint p)
    {
    _previousPoints.addElement(p);
    commit();
    }
    /
    Removes a waypoint from the set of saved points and
  • commits the modifed set to flash memory.
  • @param p the point to remove
    /
    /
    package/
    synchronized static void removeWayPoint(WayPoint p)
    {
    _previousPoints.removeElement(p);
    commit();
    }
    // Commit the waypoint set to flash memory.
    private static void commit()
    {
    _store.setContents(_previousPoints);
    _store.commit();
    }
    /
    Implementation of the LocationListener interface.
    /
    private class LocationListenerImpl implements LocationListener
    {
    // Members. ————————————————————–
    private int captureCount;
    // Methods. ————————————————————–
    public void locationUpdated(LocationProvider provider, Location location)
    {
    if(location.isValid())
    {
    float heading = location.getCourse();
    double longitude = location.getQualifiedCoordinates().getLongitude();
    double latitude = location.getQualifiedCoordinates().getLatitude();
    float altitude = location.getQualifiedCoordinates().getAltitude();
    float speed = location.getSpeed();
    // Horizontal distance.
    float horizontalDistance = speed * _interval;
    _horizontalDistance += horizontalDistance;
    // Horizontal distance for this waypoint.
    _wayHorizontalDistance += horizontalDistance;
    // Distance over the current interval.
    float totalDist = 0;
    // Moving average grade.
    for(int i = 0; i 0) _verticalDistance = _verticalDistance + altGain;
    captureCount += _interval;
    // If we’re mod zero then it’s time to record this data.
    captureCount %= CAPTURE_INTERVAL;
    // Information to display on the device.
    StringBuffer sb = new StringBuffer();
    sb.append(“Longitude: “ + longitude+ “\n”);
    sb.append(“Latitude: “ + latitude+ “\n”);
    sb.append(“Altitude: “ + altitude + “ m\n”);
    sb.append(“Heading relative to true north: “ + heading + “\n”);
    sb.append(“Speed : “ + speed + +” m/s\n”);
    sb.append(“Grade : “);
    if(Float.isNaN(grade))
    sb.append(“ Not available”);
    else
    sb.append(grade+” %”);
    GPSDemo.this.updateLocationScreen(sb.toString());
    }
    }
    public void providerStateChanged(LocationProvider provider, int newState)
    {
    // No operation defined.
    }
    }
    /
    WayPoint describes a way point, a marker on a journey or point of interest.
  • WayPoints are persistable.
  • package
    */
    static class WayPoint implements Persistable
    {
    public long _startTime;
    public long _endTime;
    public float _distance;
    public float _verticalDistance;
    public WayPoint(long startTime,long endTime,float distance,float verticalDistance)
    {
    _startTime=startTime;
    _endTime=endTime;
    _distance=distance;
    _verticalDistance=verticalDistance;
    }
    }
    }`

Entradas relacionadas:

Un ejemplo de aplicación Java para BlackBerry – Parte I

Un ejemplo de aplicación Java para BlackBerry – Parte II

Un ejemplo de aplicación Java para BlackBerry – Parte III

Un ejemplo de aplicación Java para BlackBerry – Parte IV y final

Leyendo nuestro GPS desde Java con la JavaME Location API (JSR-179) – Parte I