0

У меня есть опыт работы с Android, но я не знаю, как использовать API Карт Google и службы определения местоположения. Я пытаюсь показать движение пользователя на MapFragment, перемещая трекер и рисуя полилинию, где был пользователь, вроде MapMyRun.Отслеживание местоположения пользователя в режиме реального времени с использованием Polylines на Картах Google (Android)

Из того, что я видел в своем отладчике, я получаю местоположение после возобновления фрагмента и прилагается к списку LatLngs. Мне нужно, чтобы карта обновлялась каждые несколько секунд или каждый раз, когда местоположение менялось на десятую часть мили или около того.

Вот что у меня есть для деятельности, содержащей MapFragment. Мой инстинкт подсказывает мне, что мне нужно что-то сделать внутри метода handleNewLocation, который обновит карту ... либо это, либо, возможно, что-то сделает в LocationProvider, который будет чаще обновлять местоположение.

Любая помощь, советы или ссылки были бы очень признательны! Моя цель - научиться, чтобы я понял, как я могу сделать это лучше в будущем :)!

package com.seniorproject.trafton.trackrecordrace; 

//Import statements not shown for readability 
import... 

public class MapsActivity extends AppCompatActivity implements LocationProvider.LocationCallback { 

public static final String TAG = "cloudsTraf"; 
     //MapsActivity.class.getSimpleName(); 

private GoogleMap mMap; // Might be null if Google Play services APK is not available. 

private LocationProvider mLocationProvider; 

//variable for toggle buttons 
private boolean isRunning = false; 

//ArrayList to store geopoints for current run 
private ArrayList<LatLng> geoPoints; 

//Array of distances 
private ArrayList<Float> distances; 

//total distance 
private float totalDistance; 

//polyline that represented the route 
Polyline tracker; 

/*Load up widgets for tracking */ 
private ImageButton mPlayButton; 
private ImageButton mPauseButton; 

private TextView mRunTimeText; 
private TextView mRunSpeedText; 
private TextView mRunDistText; 
private TextView mRunCalsText; 

private Boolean mIsPlayButtonClicked; 

//Handler to control timer tracking 
//Thank you to Nikos Maravitsas for the tutorial on timers 

private Handler timeHandler = new Handler(); 

private long startTime = 0L; 
long timeInMillis = 0L; 
long timeSwapBuffer = 0L; 
long updatedTime = 0L; 





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

    mLocationProvider = new LocationProvider(this, this); 
    geoPoints = new ArrayList<LatLng>(); //added 

    //Add in code to inflate the tracking modules 
    mRunTimeText = (TextView) findViewById(R.id.run_time_text); 
    mRunDistText = (TextView) findViewById(R.id.run_dist_text); 
    mRunSpeedText = (TextView) findViewById(R.id.run_speed_text); 

    Toolbar runToolbar= (Toolbar) findViewById(R.id.toolbar_run); 
    runToolbar.setTitle("Run on " + getDate()); 
    runToolbar.setTitleTextColor(Color.WHITE); 
    setSupportActionBar(runToolbar); 

} 

//Inflate the menu for the toolbar 
public boolean onCreateOptionsMenu(Menu menu) { 
    Log.e("XXX", "Menu created"); 
    MenuInflater inflater = getMenuInflater(); 
    inflater.inflate(R.menu.menu_maps_run, menu); 
    return super.onCreateOptionsMenu(menu); 
} 

//Handles possibilities of menu items being selected. 
@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    // Handle item selection 
    switch (item.getItemId()) { 
     case R.id.action_begin_run: 
      if (!isRunning) { 
       startTime = SystemClock.uptimeMillis(); 
       timeHandler.postDelayed(updateTimerThread,0); 
       item.setIcon(R.drawable.ic_pause_white_24dp); 
       isRunning = true; 
      } 
      else { 
       timeSwapBuffer += timeInMillis; 
       timeHandler.removeCallbacks(updateTimerThread); 
       item.setIcon(R.drawable.ic_play_arrow_white_24dp); 
       isRunning = false; 

      } 
      return true; 

     case R.id.action_stop_run: 
      //stop run, save run, and transport user to the stats for that run 

      return true; 
     default: 
      return super.onOptionsItemSelected(item); 
    } 
} 

/*Code to update the timer, begins a new timer thread.*/ 
private Runnable updateTimerThread = new Runnable() { 
    public void run(){ 
     timeInMillis = SystemClock.uptimeMillis() - startTime; 
     updatedTime = timeSwapBuffer + timeInMillis; 

     //Get integer value from time update and put into textView 
     int seconds = (int) (updatedTime/1000); 
     //need two seconds variables for formatting purposes. 
     int secs = seconds % 60; 
     int mins = (seconds/60); 
     int hours = (mins/60); 

     mRunTimeText.setText("" + hours + ":" + 
       String.format("%02d", mins) + ":" + 
       String.format("%02d", secs)); 
     timeHandler.postDelayed(this, 0); 
    } 

}; 

/* */ 

@Override 
protected void onResume() { 
    super.onResume(); 
    setUpMapIfNeeded(); 
    mLocationProvider.connect(); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    mLocationProvider.disconnect(); 
} 

/** 
* Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly 
* installed) and the map has not already been instantiated.. This will ensure that we only ever 
* call {@link #setUpMap()} once when {@link #mMap} is not null. 
* <p/> 
* If it isn't installed {@link SupportMapFragment} (and 
* {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to 
* install/update the Google Play services APK on their device. 
* <p/> 
* A user can return to this FragmentActivity after following the prompt and correctly 
* installing/updating/enabling the Google Play services. Since the FragmentActivity may not 
* have been completely destroyed during this process (it is likely that it would only be 
* stopped or paused), {@link #onCreate(Bundle)} may not be called again so we should call this 
* method in {@link #onResume()} to guarantee that it will be called. 
*/ 
private void setUpMapIfNeeded() { 
    // Do a null check to confirm that we have not already instantiated the map. 
    if (mMap == null) { 
     // Try to obtain the map from the SupportMapFragment. 
     mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)) 
       .getMap(); 
     // Check if we were successful in obtaining the map. 
     if (mMap != null) { 
      setUpMap(); 
     } 
    } 
} 

/** 
* This should only be called once and when we are sure that {@link #mMap} is not null. 
*/ 
private void setUpMap() { 
    //mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker")); 
} 

//handle new location 
public void handleNewLocation(Location location) { 
    Log.d(TAG, location.toString()); 

    double currentLatitude = location.getLatitude(); 
    double currentLongitude = location.getLongitude(); 
    LatLng latLng = new LatLng(currentLatitude, currentLongitude); 

    //Get the new geopoints to redraw the line on each iteration 
    geoPoints.add(latLng); 
    //get the latest distance update 
    if (geoPoints.size() > 2) { 
     calculateDistance(); 
    } 
    //set the distance test 
    mRunDistText.setText(Float.toString(totalDistance) + " Meters"); 
    mRunSpeedText.setText((location.getSpeed() + " m/s")); 

    //draw the polyline 
    drawRoute(); 
    MarkerOptions options = new MarkerOptions() 
      .position(latLng) 
      .title("I am here!"); 
    mMap.addMarker(options); 
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,15)); 
} 

/* 
*Methods to calculate metrics. All measurements returned are approximations. 
*/ 
//returns the latest distance between geoPoints. Append to total number 
public void calculateDistance(){ 
    Location newLoc = new Location("Latest Location"); 
    Location oldLoc = new Location("Last known Location"); 
    LatLng newPt = geoPoints.get(geoPoints.size()- 1); 
    LatLng oldPt = geoPoints.get(geoPoints.size()-2); 
    distances.add(oldLoc.distanceTo(newLoc)); 
    //add to the distance variable 
    totalDistance = totalDistance + oldLoc.distanceTo(newLoc); 
    Log.d(TAG, "distance between points is: " + oldLoc.distanceTo(newLoc)); 
} 

//calculates the current KCals being burned 
public void calculateKcals(){ 

} 

//get today's date in a simple format 
public String getDate(){ 
    Date today = Calendar.getInstance().getTime(); 
    SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd"); 
    String todaysDate = formatter.format(today); 
    return todaysDate; 
} 

//method to draw polyline. Uses the recorded geopoints. 
public void drawRoute(){ 
    mMap.clear(); 
    PolylineOptions options = new PolylineOptions().width(5).color(android.R.color.holo_blue_dark).geodesic(true).visible(true); 
    for(int i = 0; i < geoPoints.size(); i++){ 
     LatLng pt = geoPoints.get(i); 
     options.add(pt); 
    } 
    Log.d(TAG,"GeoPoints recorded: " + geoPoints); 
    mMap.addPolyline(options); 
} 

}

Я захватывая место в другом файле (Потому что, y'know, модульность хорошо.). Если есть какие-либо дополнительные данные, которые я могу предоставить, я был бы более чем счастлив включить его!

package com.seniorproject.trafton.trackrecordrace; 

import android.app.Activity; 
import android.content.Context; 
import android.content.IntentSender; 
import android.location.Location; 
import android.os.Bundle; 
import android.util.Log; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.location.LocationListener; 
import com.google.android.gms.location.LocationRequest; 
import com.google.android.gms.location.LocationServices; 


public class LocationProvider implements 
    GoogleApiClient.ConnectionCallbacks, 
    GoogleApiClient.OnConnectionFailedListener, 
    LocationListener { 

public abstract interface LocationCallback { 
    public void handleNewLocation(Location location); 
} 

public static final String TAG = LocationProvider.class.getSimpleName(); 

/* 
* Define a request code to send to Google Play services 
* This code is returned in Activity.onActivityResult 
*/ 
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; 

private LocationCallback mLocationCallback; 
private Context mContext; 
private GoogleApiClient mGoogleApiClient; 
private LocationRequest mLocationRequest; 


public LocationProvider(Context context, LocationCallback callback) { 
    mGoogleApiClient = new GoogleApiClient.Builder(context) 
      .addConnectionCallbacks(this) 
      .addOnConnectionFailedListener(this) 
      .addApi(LocationServices.API) 
      .build(); 

    mLocationCallback = callback; 

    // Create the LocationRequest object 
    mLocationRequest = LocationRequest.create() 
      .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) 
      .setInterval(3 * 1000)  // 10 seconds, in milliseconds 
      .setFastestInterval(1 * 1000); // 1 second, in milliseconds 

    mContext = context; 
} 

public void connect() { 
    mGoogleApiClient.connect(); 
} 

public void disconnect() { 
    if (mGoogleApiClient.isConnected()) { 
     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); 
     mGoogleApiClient.disconnect(); 
    } 
} 

@Override 
public void onConnected(Bundle bundle) { 
    Log.i(TAG, "Location services connected."); 

    Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); 
    if (location == null) { 
     LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); 
    } 
    else { 
     mLocationCallback.handleNewLocation(location); 
    } 
} 

@Override 
public void onConnectionSuspended(int i) { 

} 

@Override 
public void onConnectionFailed(ConnectionResult connectionResult) { 
    /* 
    * Google Play services can resolve some errors it detects. 
    * If the error has a resolution, try sending an Intent to 
    * start a Google Play services activity that can resolve 
    * error. 
    */ 
    if (connectionResult.hasResolution() && mContext instanceof Activity) { 
     try { 
      Activity activity = (Activity)mContext; 
      // Start an Activity that tries to resolve the error 
      connectionResult.startResolutionForResult(activity, CONNECTION_FAILURE_RESOLUTION_REQUEST); 
     /* 
     * Thrown if Google Play services canceled the original 
     * PendingIntent 
     */ 
     } catch (IntentSender.SendIntentException e) { 
      // Log the error 
      e.printStackTrace(); 
     } 
    } else { 
     /* 
     * If no resolution is available, display a dialog to the 
     * user with the error. 
     */ 
     Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode()); 
    } 
} 

@Override 
public void onLocationChanged(Location location) { 
    mLocationCallback.handleNewLocation(location); 
    Log.i(TAG, "New location received "); 
} 

}

+0

Попробуйте прочитать это [SO вопрос] (http://stackoverflow.com/questions/19407929/ динамически трассировка-а-маршрут-в-режим реального времени, использующего-Google-Maps-API-для-андроида). Это возможный дубликат вашего вопроса. – abielita

ответ

0

Чтобы нарисовать полилинию на карте сделать это в onLocationChanged

Polyline route = mMap.addPolyline(new PolylineOptions()); 
route.setPoints(mGeoPoints);`