1

我为我最后一年的项目创建了一个距离计算器。计算器应显示用户当前位置,然后按下时在地图上显示一个标记。将显示从用户当前位置到标记的距离。

我已经检索了用户位置并将其存储为我在代码中使用的变量,但我得到了java.lang.IllegalStateException: System services not available to Activities before onCreate()错误。我尝试从一开始就将我的代码放在onCreate()方法中,但这也不起作用。任何帮助将不胜感激。我已经尝试了几个小时让它工作,但没有运气。当我尝试将其放入其中(LocationManager)getSystemService(Context.LOCATION_SERVICE);时,onCreate()它需要获得许可,并且我已经尝试了所有方法。

这是我的代码

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+")";

    }
}

抛出的错误

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) 
4

2 回答 2

5

我被抛出 java.lang.IllegalStateException: System services not available to Activities before onCreate() 错误。

那是因为您试图调用从字段初始值设定项中继承的方法Activity,例如。getSystemService()这行不通。在onCreate()调用super.onCreate()类似getSystemService().

我尝试将我的代码从一开始就放在 onCreate() 方法中,但这也不起作用。

这个示例应用程序中,我得到了LocationManager一个onCreate()片段:

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

    template=getActivity().getString(R.string.url);
    mgr=
        (LocationManager)getActivity().getSystemService(Context.LOCATION_SERVICE);
  }

同样的原则也适用于onCreate()一项活动。

当我尝试放置 (LocationManager)getSystemService(Context.LOCATION_SERVICE); 在 onCreate() 它需要一个权限

您需要<uses-permission>在清单中有一个元素 for ACCESS_FINE_LOCATIONor ACCESS_COARSE_LOCATION,这取决于您是否打算使用GPS_PROVIDERor NETWORK_PROVIDER

在 Android 6.0+ 上,如果您targetSdkVersion是 23 或更高版本,则需要实现运行时权限,因为这些权限是dangerous.

于 2016-03-22T15:42:26.423 回答
0

您尝试在构造函数中获取上下文和服务。这是错误的。构造函数在对象被创建时执行,在它被附加到 Android 框架之前。

只需将成员初始化移动到onCreate()

于 2016-03-22T15:42:24.497 回答