I have created a distance calculator for my final year project. The calculator should display the users current location and then display a marker on the map when pressed. The distance will be displayed from the users current location to the marker.
I have retrieved the users location and stored as a variable which I use in my code but I get thrown with the java.lang.IllegalStateException: System services not available to Activities before onCreate()
error. I've tried placing my code from the start in the onCreate()
method but this doesn't work either. Any help would be greatly appreciated. I have been trying for hours to get it working but no luck. When I try to place the (LocationManager)getSystemService(Context.LOCATION_SERVICE);
in the onCreate()
it requires a permission and I've tried everything.
Here is my code
package com.example.matthewmcnabb.moyola;
import android.Manifest;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.view.View;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import java.io.IOException;
import java.util.List;
public class MapsActivity extends FragmentActivity {
// the Google Map object
private GoogleMap mMap;
private LocationManager locationManager;
private Location mCurrentLocation;
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
public Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
private double longitude = location.getLongitude();
private double latitude = location.getLatitude();
private LatLng STARTING_MARKER_POSITION =new LatLng(longitude, latitude);
private LatLng distanceFrom = STARTING_MARKER_POSITION;
// line will be drawn at the click event
private Polyline line=null;
// A Geocoder can transform a pair of latitude/longitude into a street address and viceversa.
// We'll use it in the listener
private static Geocoder geocoder=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// we set the layout for the Activity
setContentView(R.layout.activity_maps);
// the geocoder is instantiated for the first time
geocoder=new Geocoder(this);
// if there isn't a map, it will be created
setUpMapIfNeeded();
}
private GoogleMap.OnMapClickListener clickListener=new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(final LatLng pos) {
// this method is called when the user taps the map
// if a line already appears, it's removed
if (line!=null)
line.remove();
// a new line is created
line = mMap.addPolyline(new PolylineOptions()
.add(distanceFrom, pos)
.width(5) // width of the line
.color(Color.RED)); // line color
// call the converter object for geocoding invocation and distance calculation
new AddressConverter().execute(distanceFrom, pos);
}
};
@Override
protected void onResume() {
super.onResume();
// the availability of the GoogleMap will be checked before the Activity starts interacting with the user
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// the map is created only it has not been initialized
if (mMap == null) {
// the map is located in the layout
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
// if a map exists, we proceed with initialization
if (mMap != null) {
setUpMap();
}
}
}
// Now it's time to configure the map. We can add markers, shapes, event handlers and so on
private void setUpMap() {
// the camera will be positioned according to the new coordinates
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(STARTING_MARKER_POSITION, 16));
// we choose the type of the map: Satellite in this case
mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
// markerOptions describes the marker we want to place
MarkerOptions markerOptions=new MarkerOptions()
.position(STARTING_MARKER_POSITION)
.draggable(true);
// the marker has to be draggable as we'll move it
// the marker is rendered on the map
mMap.addMarker(markerOptions);
// we define the object to invoke when the marker is dragged
mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener()
{
@Override
public void onMarkerDragStart(Marker arg0)
{
// this method is called when the drag starts
// the operation we need is the cancellation of a preexisting line
if (line!=null)
line.remove();
}
@Override
public void onMarkerDragEnd(final Marker pos)
{
// we get the final position of the marker
distanceFrom=pos.getPosition();
}
@Override
public void onMarkerDrag(Marker arg0)
{
// operations performed during the movement. Nothing to do
}
});
// the callback to invoke is set
mMap.setOnMapClickListener(clickListener);
}
// we want to know which address corresponds to this location
// we use AsyncTask to perform slower operations on a separate thread
private class AddressConverter extends AsyncTask<LatLng,Void,String>
{
// The ProgressDialog window we'll show during the calculation
private ProgressDialog progress=null;
// this method is called before the background job starts. It works on the main thread
@Override
protected void onPreExecute() {
// ProgressDialog is shown
progress= ProgressDialog.show(MapsActivity.this,"Distance calculator","We are calcultating the distance...", true,false);
}
// this method works on a separate thread
// it performs geocoding operations to retrieve the address of the points and calculates the distance in meters between them
@Override
protected String doInBackground(LatLng... params) {
float[] distance=new float[1];
try {
// the Location class contains what we need to calculate distances
Location.distanceBetween(params[0].latitude,params[0].longitude,params[1].latitude,params[1].longitude,distance);
// geocoding operations
List<Address> fromResult=geocoder.getFromLocation(params[0].latitude,params[0].longitude,1);
List<Address> toResult=geocoder.getFromLocation(params[1].latitude,params[1].longitude,1);
// the message informs the user about the distance from the marker to the point selected with the click
// if we have got both the addresses, we use them to compose the message, otherwise we show only the distance
if (fromResult.size()>0 && toResult.size()>0)
{
return "The distance is " + Math.round(distance[0]) + " meters";
}
else
return "The distance is " + Math.round(distance[0]) + " meters";
}
catch (IOException e) {
return "The distance is " + Math.round(distance[0]) + " meters";
}
}
@Override
protected void onPostExecute(String message)
{
if (progress!=null)
progress.dismiss();
// The builder of the window is instantiated
AlertDialog.Builder builder=new AlertDialog.Builder(MapsActivity.this);
builder.setTitle("Distance");
builder.setMessage(message);
// the Alert dialog appears
builder.show();
}
}
// this method only formats the message with addresses
private String getAddressDescription(Address a)
{
String city=a.getLocality();
String address=a.getAddressLine(0);
return "'"+address+"' ("+city+")";
}
}
The error thrown
FATAL EXCEPTION: main
Process: com.example.matthewmcnabb.moyola, PID: 27349
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.matthewmcnabb.moyola/com.example.matthewmcnabb.moyola.MapsActivity}: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2515)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2723)
at android.app.ActivityThread.access$900(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1422)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5832)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Caused by: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:5259)
at com.example.matthewmcnabb.moyola.MapsActivity.<init>(MapsActivity.java:51)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1650)
at android.app.Instrumentation.newActivity(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2505)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2723)
at android.app.ActivityThread.access$900(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1422)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5832)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)