简体   繁体   中英

Android Service for GPS updates

I'm trying to write a simple app that receives location info from GPS and plots the points on a map. I wrote a Service for GPS handling but I'm having trouble with using it in an Activity - I'm unable to get values of latitude/longitude/altitude.

The Service appears to start correctly (GPS is initiated on the phone and acquires a fix) but when I try to retrieve coordinates (by pressing the button in Activity to call relevant methods) the app crashes and I get a java.lang.NullPointerException error in LogCat.

I've looked at many examples on Stack Overflow and other website but I'm new to Android development and I'm not sure what I'm doing wrong. I would greatly appreciate any advice.

Service:

public class TrackingService extends Service {
private LocationManager SgpstLocationManager;
private LocationListener spgstLocationListener;

private static long minimumDistanceBwUpdates = 10; //10 metres
private static long minimumTimeBwUpdates = 3000; //3 seconds 

static Location location;

private void startTrackingService() {
    //location manager declaration
    SgpstLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    //location listener declaration
    spgstLocationListener = new SgpstLocationListener();

    //request location updates from location manager
    SgpstLocationManager.requestLocationUpdates(
            SgpstLocationManager.GPS_PROVIDER, 
            minimumTimeBwUpdates,
            minimumDistanceBwUpdates,
            spgstLocationListener);
}

private void stopTrackingService() {
    //remove location updates from location manager
    SgpstLocationManager.removeUpdates(spgstLocationListener);
}

//location listener class
public class SgpstLocationListener implements LocationListener {
    public void onLocationChanged(Location location) {
        if (location != null) {
            try {
                if (location.hasAccuracy()) {
                    //retrieve information about a point:
                    location.getLatitude();
                    location.getLongitude();
                }                   
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public void onProviderDisabled(String provider) {
        //mandatory method - not used
    }

    public void onProviderEnabled(String provider) {
        //mandatory method - not used
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        //mandatory method - not used
    }
}

//mandatory service methods
public void onCreate() {
    super.onCreate();
    startTrackingService();
}

public void onDestroy() {
    super.onDestroy();
    stopTrackingService();
}

//methods for interaction with client objects
private final IBinder sgpstBinder = new LocalBinder();

@Override
public IBinder onBind(Intent intent) {
    return sgpstBinder;
}

public class LocalBinder extends Binder {
    TrackingService getService() {
        return TrackingService.this;
    }
}

//get and set methods
public static void setMinimumDistanceBwUpdates(long distance) {
    minimumDistanceBwUpdates = distance;
}

public static void setMinimumTimeBwUpdates(long time) {
    minimumTimeBwUpdates = time;
}

public static long getMinimumDistanceBwUpdates() {
    return minimumDistanceBwUpdates;
}

public static long getMinimumTimeBwUpdates() {
    return minimumTimeBwUpdates;
}

public static double getMyLatitude() {
    return location.getAltitude();
}

public static double getMyLongitude() {
    return location.getLongitude();
}

public static double getMyAltitude() {
    return location.getAltitude();
}

}

Activity:

public class GPSTestActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_gpstest);

    startService(new Intent(GPSTestActivity.this, TrackingService.class));

    Button updateButton = (Button)findViewById(R.id.update_button);
    final TextView latitudeText = (TextView)findViewById(R.id.latitude);
    final TextView longitudeText = (TextView)findViewById(R.id.longitude);
    final TextView altitudeText = (TextView)findViewById(R.id.altitude);
    latitudeText.setText("latitude");
    longitudeText.setText("longitude");
    altitudeText.setText("altitude");

    updateButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
                latitudeText.setText(String.valueOf(TrackingService.getMyLatitude()));
                longitudeText.setText(String.valueOf(TrackingService.getMyLongitude()));
                altitudeText.setText(String.valueOf(TrackingService.getMyAltitude()));
            }
    });
}

Many thanks for help. I rewrote/refactored the code based on your suggestions. I am now receiving the following error:

java.lang.RuntimeException: Unable to instantiate activity
ComponentInfo{com.example.simplegpstracker/com.example.simplegpstracker.GPSTestActivity}: java.lang.NullPointerException

I'll try to read up on Services Binding myself but any advice would be welcome.

amended code:

service:

public class TrackingService extends Service {
//fields
private LocationManager SgpstLocationManager;
private LocationListener spgstLocationListener;

private static long minimumDistanceBwUpdates = 10; //10 metres
private static long minimumTimeBwUpdates = 3000; //3 seconds 

static Location myLocation;

private void startTrackingService() {
    //location manager declaration
    SgpstLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

    //location listener declaration
    spgstLocationListener = new SgpstLocationListener();

    //request location updates from location manager
    SgpstLocationManager.requestLocationUpdates(
            SgpstLocationManager.GPS_PROVIDER, 
            minimumTimeBwUpdates,
            minimumDistanceBwUpdates,
            spgstLocationListener);
}

private void stopTrackingService() {
    //remove location updates from location manager
    SgpstLocationManager.removeUpdates(spgstLocationListener);
}

//location listener class
public class SgpstLocationListener implements LocationListener {
    public void onLocationChanged(Location location) {
        if (location != null) {
            try {
                if (location.hasAccuracy()) {
                    //retrieve information about a point:
                    myLocation = location;
                }                   
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public void onProviderDisabled(String provider) {
        //mandatory method - not used
    }

    public void onProviderEnabled(String provider) {
        //mandatory method - not used
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        //mandatory method - not used
    }
}

//mandatory service methods
public void onCreate() {
    super.onCreate();
    startTrackingService();
}

public void onDestroy() {
    super.onDestroy();
    stopTrackingService();
}

//methods for interaction with client objects
private final IBinder sgpstBinder = new LocalBinder();

@Override
public IBinder onBind(Intent intent) {
    return sgpstBinder;
}

public class LocalBinder extends Binder {
    TrackingService getService() {
        return TrackingService.this;
    }
}

//get and set methods
public static void setMinimumDistanceBwUpdates(long distance) {
    minimumDistanceBwUpdates = distance;
}

public static void setMinimumTimeBwUpdates(long time) {
    minimumTimeBwUpdates = time;
}

public static long getMinimumDistanceBwUpdates() {
    return minimumDistanceBwUpdates;
}

public static long getMinimumTimeBwUpdates() {
    return minimumTimeBwUpdates;
}

public static double getMyLatitude() {
    return myLocation.getAltitude();
}

public static double getMyLongitude() {
    return myLocation.getLongitude();
}

public static double getMyAltitude() {
    return myLocation.getAltitude();
}

}

activity:

public class GPSTestActivity extends Activity {

boolean trackingServiceBounded;
TrackingService trackingService;
TextView latitudeText = (TextView)findViewById(R.id.latitude);
TextView longitudeText = (TextView)findViewById(R.id.longitude);
TextView altitudeText = (TextView)findViewById(R.id.altitude);
Button updateButton = (Button)findViewById(R.id.update_button);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_gpstest);

    //startService(new Intent(GPSTestActivity.this, TrackingService.class));

    latitudeText.setText("latitude");
    longitudeText.setText("longitude");
    altitudeText.setText("altitude");

    updateButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
                latitudeText.setText(String.valueOf(TrackingService.getMyLatitude()));
                longitudeText.setText(String.valueOf(TrackingService.getMyLongitude()));
                altitudeText.setText(String.valueOf(TrackingService.getMyAltitude()));
            }
    });
}

@Override
protected void onStart() {
    super.onStart();
    Intent intent = new Intent(this, TrackingService.class);
    bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}

//bind Activity to the Service
ServiceConnection serviceConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName name, IBinder service) {
        trackingServiceBounded = true;
        LocalBinder localBinder = (LocalBinder)service;
        trackingService = localBinder.getService();
    }

    public void onServiceDisconnected(ComponentName name) {
        trackingServiceBounded = false;
        trackingService = null;
    }
};

@Override
protected void onStop() {
    super.onStop();
    if (trackingServiceBounded) {
        unbindService(serviceConnection);
        trackingServiceBounded = false;
    }
}

}

To get the instance of your service you need to bind the service with the activity. Check these links:

http://developer.android.com/guide/components/bound-services.html http://dharmendra4android.blogspot.mx/2012/05/bind-service-using-ibinder-class.html

If you need aditional help, plese tell me.

You declare location but never instantiate it.
Do this at onLocationChange

if (location.hasAccuracy()) {
                    //save location in the private variable:
                    this.location = location;
                }  

To have a cleaner code move the SgpstLocationListener class to another file.
As you like more i will rename CurrentLocation to myLocation.

//location listener class
public class SgpstLocationListener implements LocationListener {

    public Location myLocation; //THIS IS WHAT YOU READ IN THE SERVICE

    public void onLocationChanged(Location location) {
        if (location != null) {
            try {
                if (location.hasAccuracy()) {
                    //retrieve information about a point:
                    myLocation = location; //SET TO THE CURRENT POSITION
                }                   
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public void onProviderDisabled(String provider) {
        //mandatory method - not used
    }

    public void onProviderEnabled(String provider) {
        //mandatory method - not used
    }

    public void onStatusChanged(String provider, int status, Bundle extras) {
        //mandatory method - not used
    }
}  

In the service use this to get latitude from SgpstLocationListener

public static double getMyLatitude() {

        return spgstLocationListener.myLocation.getLatitude();
    }  

Before proceeding you must be sure that the GPS is working !!

As you may have already noticed my english is not very good, I hope you understood

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM