Получить местоположение пользователя на Android

Я хотел бы разработать приложение металлоискателя для Android, и для этого я использую магнитометр вместе с классом GeomagnField. Это то, что я делаю:

  1. Получите значения x, y, z из магнитометра и рассчитайте магнитное поле как x^2 + y^2 + z^2.
  2. Рассчитайте геомагнитное поле, используя единственный конструктор, заданный классом GeomagnField. Чтобы вычислить мои координаты, я использую диспетчер местоположения и другие связанные с ним классы.
  3. Сравните эти магнитные поля, чтобы обнаружить металл.

Вот мой код:

public class MainActivity extends AppCompatActivity implements SensorEventListener, LocationListener {

    SensorManager man;
    Sensor sensor;
    SensorEventListener thisActivity = this;
    double earthField;
    Location l;
    LocationManager locationManager;

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

        man = (SensorManager) getSystemService(SENSOR_SERVICE);
        sensor = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

        l = getLocation();
        if(l != null)
        {
            GeomagneticField gmf = new GeomagneticField((float) l.getLatitude(),
                    (float) l.getLongitude(),
                    (float) l.getAltitude(),
                    l.getTime());
            earthField = getEarthField(gmf);
        }
        else
        {
            ((TextView)findViewById(R.id.debug)).setText("l è nullo");
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        man.unregisterListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();

        man.registerListener(thisActivity,
                sensor,
                Sensor.TYPE_MAGNETIC_FIELD,
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];
        float magneticField = (float) getField(x, y, z);

        ((TextView) findViewById(R.id.xreading)).setText("X: " + x + "");
        ((TextView) findViewById(R.id.yreading)).setText("Y: " + y + "");
        ((TextView) findViewById(R.id.zreading)).setText("Z: " + z + "");

        ((TextView) findViewById(R.id.earthTxt)).setText("Earth: " + earthField);
        ((TextView) findViewById(R.id.fieldTxt)).setText("Calculated: " + magneticField);

        // I'm not sure i have to repeat this step inside OnSensorChanged.
        // Instructions inside the if statement are executed by onCreate, too.
        if(l != null)
        {
            GeomagneticField gmf = new GeomagneticField((float) l.getLatitude(),
                    (float) l.getLongitude(),
                    (float) l.getAltitude(),
                    l.getTime());
            earthField = getEarthField(gmf);
        }


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

        if (magneticField > 1.4*earthField || magneticField < 0.6*earthField) {
            //there is a high probability that some metal is close to the sensor
            metalNearby.setText("Ho rilevato un metallo");
        }
        else {
            metalNearby.setText("Sto cercando...");
        }
    }

    private double getEarthField(GeomagneticField gmf) {
        return getField(gmf.getX(), gmf.getY(), gmf.getZ());
    }

    private double getField(float x, float y, float z) {
        return Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) { }

    public Location getLocation()
    {
        Location location = null;
        try
        {
            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);

            // Creating an empty criteria object
            Criteria criteria = new Criteria();

            // Getting the name of the provider that meets the criteria
            String provider = locationManager.getBestProvider(criteria, false);

            try
            {
                location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            }
            catch (SecurityException e)
            {
                e.printStackTrace();
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }

        finally
        {
            return location;
        }
    }

    @Override
    public void onLocationChanged(Location location)
    {
        l = location;
    }

Моя проблема в том, что переменная earthField всегда оценивается в 0.0, и это заставляет меня думать, что метод getLocation (определенный пользователем) всегда возвращает нуль. Что я делаю неправильно?

1 ответ

Если вам нужно новое местоположение через какое-то время или каждые несколько пройденных метров, попробуйте использовать такой код:

public void getLocation() {
        try {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
            boolean isGPSEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            boolean isNetworkEnabled = mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (isNetworkEnabled) {
                mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, mLocationListener);
            }

            if (isGPSEnabled) {
                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, mLocationListener);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

MIN_TIME - на этот раз, так как система получит местоположение

MIN_DISTANCE - то же самое, только с расстоянием

mLocationListener - ваш слушатель, где вы получите местоположение

Другие вопросы по тегам