2014-01-23 4 views
3

Согласно sample app, который находит местоположение пользователя, что это хорошая идея, чтобы отслеживать изменения местоположения в деятельности:LocationListener и утечка памяти

class MyActivity extends Activity implements LocationListener { 
    @Inject 
    private LocationManager locationManager; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); 
    } 

    @Override 
    public void onLocationChanged(Location location) { 
     // do something with location 
    } 

    // ... 
} 

Однако, я не уверен в этом. Когда происходит изменение конфигурации, моя активность уничтожается и воссоздается, и в следующий раз регистрируется как слушатель. Ссылка на старую активность хранится в LocationManager, не так ли?

Если я извлечу LocationListener для отдельного объекта, все же у меня возникла проблема с уведомлением текущей деятельности о новом местоположении (не обязательно такой же, как запрашивающая активность).

Есть ли общий шаблон для решения этой проблемы?

+0

https://code.google.com/p/android/issues/detail?id=15170 – ecle

ответ

4

В этом примере у вас также есть еще одна проблема: ваш GPS-приемник будет работать всегда и будет разряжать аккумулятор.

Чем лучше практика:

1) зарегистрировать LocationListener в данный вид деятельности onStart()

2) удалить LocationListener в onStop()

Это исправить обе проблемы на данный вид деятельности.

Если вам нужно, чтобы ваше приложение отслеживать положение пользователя в фоновом режиме (например, GPS-трекер) использовать Service (http://developer.android.com/reference/android/app/Service.html)

+0

Разве это отличается от использования 'OnPause()' и 'onResume()'? – zundi

2

Ответ для такого рода проблемы заключается в использовании сервиса.

A Служба - это компонент приложения, который может выполнять длительные операции в фоновом режиме и не предоставляет пользовательский интерфейс. Другой компонент приложения может запустить службу, и он будет продолжать работать в фоновом режиме, даже если пользователь переключится на другое приложение.

Еще одна вещь о сервисе - это не может обновить интерфейс. Итак, какие данные вы хотите отправить в свою деятельность, вы можете сделать это с помощью намерения.

Сервис может быть специфичным для вашего приложения, или несколько приложений могут использовать одну и ту же услугу. Если услуга относится только к вашему приложению, вы должны закрыть эту службу; В противном случае он будет работать в фоновом режиме. Служба не работает в отдельной ветке.

Sample код Место слушателя как сервис

public class GPSTracker extends Service implements LocationListener { 

    private Context mContext; 
    private final String TAG = "GPSTracker"; 

    // flag for GPS status 
    boolean isGPSEnabled = false; 

    // flag for network status 
    boolean isNetworkEnabled = false; 

    // flag for GPS status 
    boolean canGetLocation = false; 

    Location location; // location 
    double latitude; // latitude 
    double longitude; // longitude 

    // The minimum distance to change Updates in meters 
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters 

    // The minimum time between updates in milliseconds 
    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute 

    // Declaring a Location Manager 
    protected LocationManager locationManager; 
    Intent intent = new Intent(MainActivity.LOCATION_CHANGE); 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Log.d(TAG,"onStartCommand"); 
     Log.d(TAG, "flag " + flags + "startId" + startId); 
     this.mContext = this; 
     getLocation(); 
     return super.onStartCommand(intent, flags, startId); 
    } 

    public Location getLocation() { 
     try { 
      locationManager = (LocationManager) mContext 
        .getSystemService(LOCATION_SERVICE); 

      // getting GPS status 
      isGPSEnabled = locationManager 
        .isProviderEnabled(LocationManager.GPS_PROVIDER); 

      // getting network status 
      isNetworkEnabled = locationManager 
        .isProviderEnabled(LocationManager.NETWORK_PROVIDER); 
      Log.d(TAG, "getlocation gpsEnabled " + isGPSEnabled + "networkenabled" 
        + isNetworkEnabled); 
      if (!isGPSEnabled && !isNetworkEnabled) { 
       Toast.makeText(mContext, "Enable GPS or Network", Toast.LENGTH_LONG).show(); 
       Log.d(TAG,"No network Provider is enabled"); 
       // no network provider is enabled 
      } else { 
       this.canGetLocation = true; 
       // First get location from Network Provider 
       if (isNetworkEnabled) { 

        locationManager.requestLocationUpdates(
          LocationManager.NETWORK_PROVIDER, 
          MIN_TIME_BW_UPDATES, 
          MIN_DISTANCE_CHANGE_FOR_UPDATES, this); 
        Log.d("Network", "Network"); 
        if (locationManager != null) { 
         location = locationManager 
           .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); 
         if (location != null) { 
          latitude = location.getLatitude(); 
          longitude = location.getLongitude(); 
          Log.d(TAG,"LAtitude :" +latitude +"Lngitude:"+longitude); 
          onLocationChanged(location); 

         } 
        } 
       } 
       // if GPS Enabled get lat/long using GPS Services 
       else if (isGPSEnabled) { 
        if (location == null) { 
         locationManager.requestLocationUpdates(
           LocationManager.GPS_PROVIDER, 
           MIN_TIME_BW_UPDATES, 
           MIN_DISTANCE_CHANGE_FOR_UPDATES, this); 
         Log.d("GPS Enabled", "GPS Enabled"); 
         if (locationManager != null) { 
          location = locationManager 
            .getLastKnownLocation(LocationManager.GPS_PROVIDER); 
          if (location != null) { 
           latitude = location.getLatitude(); 
           longitude = location.getLongitude(); 
           onLocationChanged(location); 
          } 
         } 
        } 
       } 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return location; 
    } 

    /** 
    * Stop using GPS listener 
    * Calling this function will stop using GPS in your app 
    */ 
    public void stopUsingGPS() { 
     if (locationManager != null) { 
      locationManager.removeUpdates(GPSTracker.this); 
     } 
    } 
    @Override 
    public void onDestroy() { 
     Log.d(TAG,"onDestroy Called"); 
     stopUsingGPS(); 
     super.onDestroy(); 
    } 
    @Override 
    public void onLocationChanged(Location newLocation) { 
     Log.d(TAG,"onLocationChanged new Latitude: " + newLocation.getLatitude() + 
       " \nLongitude :" + newLocation.getLongitude()); 
     intent.putExtra("latitude", newLocation.getLatitude()); 
     intent.putExtra("longitude", newLocation.getLongitude()); 
     sendBroadcast(intent); 
    } 

    @Override 
    public void onProviderDisabled(String provider) { 
    } 

    @Override 
    public void onProviderEnabled(String provider) { 
    } 

    @Override 
    public void onStatusChanged(String provider, int status, Bundle extras) { 
    } 

    @Override 
    public IBinder onBind(Intent arg0) { 
     // TODO Auto-generated method stub 
     return null; 
    } 
0
@Override 
public void onDestroy() { 
    super.onDestroy(); 
    mLocationManager.removeUpdates(locationListener); 
} 
+0

вы все равно можете получить утечку памяти с этим, хотя –

1

Вы можете сделать отдельный класс, чтобы сделать то же самое, а затем реализовать интерфейс LocationListenerFinder.onLocationChanged вашей деятельности

Теперь вы выиграли» t сталкиваются с проблемой утечки.

public class LocationListenerFinder implements LocationListener { 
    onLocationChanged onLocationChanged; 

    public LocationListenerFinder(Context context) { 
     onLocationChanged = (LocationListenerFinder.onLocationChanged) context; 
    } 
    @Override 
    public void onLocationChanged(Location location) { 
     onLocationChanged.onLocationChanged(location); 
     onLocationChanged = null; 
    } 

    public interface onLocationChanged { 
     void onLocationChanged(Location location); 
    } 
} 

В моем случае деятельность была такой ... вы можете отсылать то же самое и можете конвертировать в соответствии с вашими потребностями.

public class ActivityMapNearByPlace extends FragmentActivity implements OnMapReadyCallback, 
    GoogleApiClient.ConnectionCallbacks, 
    GoogleApiClient.OnConnectionFailedListener, LocationListenerFinder.onLocationChanged { 

private GoogleMap mMap; 
ArrayList<LatLng> listMarkerPoints; 
GoogleApiClient mGoogleApiClient; 
Location mLastLocation; 
Marker mCurrLocationMarker; 
LocationRequest mLocationRequest; 
private boolean locationPermission; 
private ArrayList<NearByPlaces> listNearByFacility; 
private int facilityPosition, locationPosition; 
private ImageView ivBack, ivMyLocation; 
private TextView tvPlaceOriginName, tvPlaceDestinationName, tvPlaceKmDistance, tvPlaceTime; 
private TableRow trPlaceTimeKm; 
private Marker currentSelectedMarker; 
private Map<Integer, Map<String, Object>> mapDistancePathData; 
private Polyline polyline; 
private boolean flagCalculatingPath = false; 
private FetchUrl fetchUrl; 
private SupportMapFragment mapFragment; 
private LocationListenerFinder locationListenerFinder; 
//private WeakLocationListener locationListener; 

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

    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
     checkLocationPermission(); 
    } else { 
     locationPermission = true; 
    } 
    // Initializing 
    listMarkerPoints = new ArrayList<>(); 
    getBundleData(); 
    listNearByFacility.get(0).getNearBy(); 
    LatLng origin = new LatLng(Double.valueOf(listNearByFacility.get(0).getGeoLocLat()), Double.valueOf(listNearByFacility.get(0).getGeoLocLong())); 
    listMarkerPoints.add(origin); 
    // Obtain the SupportMapFragment and get notified when the map is ready to be used. 
    mapFragment = (SupportMapFragment) getSupportFragmentManager() 
      .findFragmentById(R.id.map); 
    mapFragment.getMapAsync(this); 
} 

@Override 
protected void onRestart() { 
    super.onRestart(); 
    //if (mGoogleApiClient != null) mGoogleApiClient.connect(); 
} 

@Override 
protected void onStop() { 
    super.onStop(); 
    //if (mGoogleApiClient != null) mGoogleApiClient.disconnect(); 
} 

@Override 
protected void onDestroy() { 
    super.onDestroy(); 
    if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { 
     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, locationListenerFinder); 
     mGoogleApiClient.disconnect(); 
     mGoogleApiClient.unregisterConnectionCallbacks(this); 
     mGoogleApiClient.unregisterConnectionFailedListener(this); 
     // locationListener.clearData(); 
     locationListenerFinder = null; 
    } 
    mGoogleApiClient = null; 
    fetchUrl.cancel(true); 
    if (mMap != null) mMap.setMyLocationEnabled(false); 
    //if (mapFragment != null) mapFragment.onDestroy(); 
} 

@Override 
public void onBackPressed() { 
    finish(); 
} 

private void initListener() { 
    ivBack.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      onBackPressed(); 
     } 
    }); 
    ivMyLocation.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View view) { 
      if (mCurrLocationMarker.getTag() != null && !flagCalculatingPath) { 
       locationPosition = (int) mCurrLocationMarker.getTag(); 
       if (mapDistancePathData.get(locationPosition) != null) { 
        if (polyline != null) { 
         polyline.remove(); 
        } 
        Map<String, Object> hashMapDistancePathInfo = mapDistancePathData.get(locationPosition); 
        setPathInfo((String) hashMapDistancePathInfo.get("duration"), (String) hashMapDistancePathInfo.get("distance"), (PolylineOptions) hashMapDistancePathInfo.get("polyLineOptions"), "Current Location"); 
        trPlaceTimeKm.setVisibility(View.VISIBLE); 
       } else { 
        Locations locations = new Locations(); 
        locations.setName("Current Location"); 
        locations.setLatitude(String.valueOf(mLastLocation.getLatitude())); 
        locations.setLongitude(String.valueOf(mLastLocation.getLongitude())); 
        findDistanceAndMarkDirection(locations); 
       } 
      } 
      //mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); 
      //mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); 
     } 
    }); 
} 

private void initView() { 
    ivBack = (ImageView) findViewById(R.id.iv_back_btn); 
    ivMyLocation = (ImageView) findViewById(R.id.iv_my_location); 

    tvPlaceOriginName = (TextView) findViewById(R.id.tv_near_by_place_origin); 
    tvPlaceDestinationName = (TextView) findViewById(R.id.tv_near_by_place_destination); 
    tvPlaceKmDistance = (TextView) findViewById(R.id.tv_near_by_place_km); 
    tvPlaceTime = (TextView) findViewById(R.id.tv_near_by_place_time); 
    trPlaceTimeKm = (TableRow) findViewById(R.id.tr_near_by_place_km_time); 

} 

private void getBundleData() { 
    listNearByFacility = (ArrayList<NearByPlaces>) getIntent().getBundleExtra("nearByLocationBundle").getSerializable("nearByLocationData"); 
    facilityPosition = getIntent().getIntExtra("facilityPosition", 0); 
    locationPosition = getIntent().getIntExtra("locationPosition", 0); 
} 

/** 
* Manipulates the map once available. 
* This callback is triggered when the map is ready to be used. 
* This is where we can add markers or lines, add listeners or move the camera. In this case, 
* we just add a marker near Sydney, Australia. 
* If Google Play services is not installed on the device, the user will be prompted to install 
* it inside the SupportMapFragment. This method will only be triggered once the user has 
* installed Google Play services and returned to the app. 
*/ 
@Override 
public void onMapReady(GoogleMap googleMap) { 
    mMap = googleMap; 

    //Initialize Google Play Services 
    if (locationPermission) { 
     buildGoogleApiClient(); 
     checkLocationStatus(); 
     //mMap.setMyLocationEnabled(true); 
     loadMap(); 
    } 
    mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() { 
     @Override 
     public boolean onMarkerClick(Marker marker) { 
      if (marker.getTag() != null && !flagCalculatingPath) { 
       locationPosition = (int) marker.getTag(); 
       if (mapDistancePathData.get(locationPosition) != null) { 
        if (polyline != null) { 
         polyline.remove(); 
        } 
        Map<String, Object> hashMapDistancePathInfo = mapDistancePathData.get(locationPosition); 
        setPathInfo((String) hashMapDistancePathInfo.get("duration"), (String) hashMapDistancePathInfo.get("distance"), (PolylineOptions) hashMapDistancePathInfo.get("polyLineOptions"), listNearByFacility.get(0).getNearBy().get(facilityPosition).getLocations().get(locationPosition).getName()); 
        trPlaceTimeKm.setVisibility(View.VISIBLE); 
       } else { 
        findDistanceAndMarkDirection(listNearByFacility.get(0).getNearBy().get(facilityPosition).getLocations().get(locationPosition)); 
       } 
      } 
      return false; 
     } 
    }); 

    mMap.getUiSettings().setMyLocationButtonEnabled(false); 
    mMap.getUiSettings().setRotateGesturesEnabled(false); 
} 

private void loadMap() { 
    NearByPlaces originLocation = listNearByFacility.get(0); 

    if (listMarkerPoints.size() > 1) { 
     mMap.clear(); 
     listMarkerPoints.remove(1); 
    } 

    // Adding new item to the ArrayList 
    NearBy nearBy = listNearByFacility.get(0).getNearBy().get(facilityPosition); 
    tvPlaceOriginName.setText(originLocation.getProjectName()); 
    //tvPlaceDestinationName.setText(nearBy.getLocations().get(locationPosition).getName()); 
    if (mapDistancePathData == null) { 
     mapDistancePathData = new HashMap<>(); 
    } 
    // .get(locationPosition); 
    // LatLng destination = new LatLng(Double.valueOf(location.getLatitude()), Double.valueOf(location.getLongitude())); 
    //listMarkerPoints.add(destination); 

    MarkerOptions options = new MarkerOptions(); 
    options.position(listMarkerPoints.get(0)); 
    options.icon(BitmapDescriptorFactory.fromBitmap(getBitmapMarker(originLocation.getProjectName(), R.drawable.ic_marker_red))); 
    //options.title(originLocation.getProjectName()); 
    mMap.addMarker(options).showInfoWindow(); 
    for (int position = 0; position < nearBy.getLocations().size(); position++) { 
     Locations locations = nearBy.getLocations().get(position); 
     // Creating MarkerOptions 
     options = new MarkerOptions(); 
     LatLng markerPosition = new LatLng(Double.valueOf(locations.getLatitude()), Double.valueOf(locations.getLongitude())); 
     // Setting the videoPlayPosition of the marker 
     options.position(markerPosition); 
     /** 
     * For the start location, the color of marker is GREEN and 
     * for the end location, the color of marker is RED. 
     */ 
     options.icon(BitmapDescriptorFactory.fromBitmap(getBitmapMarker(locations.getName(), 0))); 
     //options.title(locationRanges.getName()); 
     // Add new marker to the Google Map Android API V2 
     Marker marker = mMap.addMarker(options); 
     // marker.showInfoWindow(); 
     marker.setTag(position); 
    } 

    findDistanceAndMarkDirection(nearBy.getLocations().get(locationPosition)); 

} 

public Bitmap getBitmapMarker(String title, int id) { 
    View customMarkerView = this.getLayoutInflater().inflate(R.layout.layout_marker_with_title, null); 
    customMarkerView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), 
      View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); 
    customMarkerView.layout(0, 0, customMarkerView.getMeasuredWidth(), customMarkerView.getMeasuredHeight()); 

    TextView tvMarkerProjectName = (TextView) customMarkerView.findViewById(R.id.tv_marker_project_name); 
    if (id != 0) { 
     ImageView ivMarkerImage = (ImageView) customMarkerView.findViewById(R.id.iv_marker_image); 
     ivMarkerImage.setImageResource(id); 
    } 

    tvMarkerProjectName.setText(title); 
    customMarkerView.setDrawingCacheEnabled(true); 
    customMarkerView.buildDrawingCache(); 
    Bitmap bm = customMarkerView.getDrawingCache(); 
    return bm; 
} 


private void findDistanceAndMarkDirection(Locations destinationLocation) { 
    flagCalculatingPath = true; 
    if (polyline != null) { 
     polyline.remove(); 
    } 
    trPlaceTimeKm.setVisibility(View.INVISIBLE); 
    tvPlaceDestinationName.setText(destinationLocation.getName()); 
    // Checks, whether start and end locationRanges are captured 
    LatLng latLngDest = new LatLng(Double.valueOf(destinationLocation.getLatitude()), Double.valueOf(destinationLocation.getLongitude())); 
    LatLng origin = listMarkerPoints.get(0); 

    // Getting URL to the Google Directions API 
    String url = getUrl(origin, latLngDest); 
    //Log.d("onMapClick", url.toString()); 
    fetchUrl = new FetchUrl(); 

    // Start downloading json data from Google Directions API 
    fetchUrl.execute(url); 
    //move map camera 
    mMap.moveCamera(CameraUpdateFactory.newLatLng(origin)); 
    mMap.animateCamera(CameraUpdateFactory.zoomTo(12)); 
} 

private void setPathInfo(String duration, String distance, PolylineOptions polylineOptions, String destName) { 
    tvPlaceTime.setText(duration); 
    tvPlaceKmDistance.setText(distance); 
    polyline = mMap.addPolyline(polylineOptions); 
    tvPlaceDestinationName.setText(destName); 
} 

private String getUrl(LatLng origin, LatLng dest) { 

    // Origin of route 
    String str_origin = "origin=" + origin.latitude + "," + origin.longitude; 

    // Destination of route 
    String str_dest = "destination=" + dest.latitude + "," + dest.longitude; 


    // Sensor enabled 
    String sensor = "sensor=false"; 

    // Building the parameters to the web service 
    String parameters = str_origin + "&" + str_dest + "&" + sensor; 

    // Output format 
    String output = "json"; 

    // Building the url to the web service 
    String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters; 


    return url; 
} 

/** 
* A method to download json data from url 
*/ 
private String downloadUrl(String strUrl) throws IOException { 
    String data = ""; 
    InputStream iStream = null; 
    HttpURLConnection urlConnection = null; 
    try { 
     URL url = new URL(strUrl); 

     // Creating an http connection to communicate with url 
     urlConnection = (HttpURLConnection) url.openConnection(); 
     urlConnection.setReadTimeout(15000 /* milliseconds */); 
     urlConnection.setConnectTimeout(15000 /* milliseconds */); 
     urlConnection.setDoInput(true); 
     // Connecting to url 
     urlConnection.connect(); 

     // Reading data from url 
     iStream = urlConnection.getInputStream(); 

     BufferedReader br = new BufferedReader(new InputStreamReader(iStream)); 

     StringBuffer sb = new StringBuffer(); 

     String line = ""; 
     while ((line = br.readLine()) != null) { 
      sb.append(line); 
     } 

     data = sb.toString(); 
     //Log.d("downloadUrl", data.toString()); 
     br.close(); 

    } catch (Exception e) { 
     // Log.d("Exception", e.toString()); 
    } finally { 
     iStream.close(); 
     urlConnection.disconnect(); 
    } 
    return data; 
} 


// Fetches data from url passed 
private class FetchUrl extends AsyncTask<String, Void, String> { 


    @Override 
    protected void onCancelled() { 
     //super.onCancelled(); 
    } 

    @Override 
    protected String doInBackground(String... url) { 

     // For storing data from web service 
     String data = ""; 

     try { 
      // Fetching the data from web service 
      data = downloadUrl(url[0]); 
      //Log.d("Background Task data", data.toString()); 
     } catch (Exception e) { 
      // Log.d("Background Task", e.toString()); 
     } 
     return data; 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     super.onPostExecute(result); 

     if (!TextUtils.isEmpty(result)) { 

      ParserTask parserTask = new ParserTask(); 

      // Invokes the thread for parsing the JSON data 
      parserTask.execute(result); 
     } else { 
      flagCalculatingPath = false; 
     } 

    } 
} 

/** 
* A class to parse the Google Places in JSON format 
*/ 
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> { 

    // Parsing the data in non-ui thread 
    @Override 
    protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) { 

     JSONObject jObject; 
     List<List<HashMap<String, String>>> routes = null; 

     try { 
      jObject = new JSONObject(jsonData[0]); 
      //Log.d("ParserTask", jsonData[0].toString()); 
      DataParser parser = new DataParser(); 
      //Log.d("ParserTask", parser.toString()); 

      // Starts parsing data 
      routes = parser.parse(jObject); 
      //Log.d("ParserTask", "Executing routes"); 
      //Log.d("ParserTask", routes.toString()); 

     } catch (Exception e) { 
      //Log.d("ParserTask", e.toString()); 
      e.printStackTrace(); 
     } 
     return routes; 
    } 

    // Executes in UI thread, after the parsing process 
    @Override 
    protected void onPostExecute(List<List<HashMap<String, String>>> result) { 
     ArrayList<LatLng> points; 
     PolylineOptions lineOptions = null; 
     HashMap<String, Object> hashMapDistancePathInfo = null; 

     // Traversing through all the routes 
     for (int i = 0; i < result.size(); i++) { 
      points = new ArrayList<>(); 
      lineOptions = new PolylineOptions(); 


      // Fetching i-th route 
      List<HashMap<String, String>> path = result.get(i); 

      // Fetching all the points in i-th route 
      for (int j = 1; j < path.size(); j++) { 
       HashMap<String, String> point = path.get(j); 

       double lat = Double.parseDouble(point.get("lat")); 
       double lng = Double.parseDouble(point.get("lng")); 
       LatLng position = new LatLng(lat, lng); 

       points.add(position); 
      } 

      // Adding all the points in the route to LineOptions 
      lineOptions.addAll(points); 
      lineOptions.width(5); 
      lineOptions.color(Color.RED); 
      tvPlaceTime.setText(path.get(0).get("duration")); 
      tvPlaceKmDistance.setText(path.get(0).get("distance")); 
      trPlaceTimeKm.setVisibility(View.VISIBLE); 

      hashMapDistancePathInfo = new HashMap<>(); 
      hashMapDistancePathInfo.put("duration", path.get(0).get("duration")); 
      hashMapDistancePathInfo.put("distance", path.get(0).get("distance")); 
      hashMapDistancePathInfo.put("polyLineOptions", lineOptions); 
      //Log.d("onPostExecute", "onPostExecute lineoptions decoded"); 

     } 
     // Drawing polyline in the Google Map for the i-th route 
     if (lineOptions != null) { 
      mapDistancePathData.put(locationPosition, hashMapDistancePathInfo); 
      polyline = mMap.addPolyline(lineOptions); 
     } else { 
      //Log.d("onPostExecute", "without Polylines drawn"); 
     } 
     flagCalculatingPath = false; 
    } 

} 

protected synchronized void buildGoogleApiClient() { 
    mGoogleApiClient = new GoogleApiClient.Builder(getApplicationContext()) 
      .addConnectionCallbacks(this) 
      .addOnConnectionFailedListener(this) 
      .addApi(LocationServices.API) 
      .build(); 
    mGoogleApiClient.connect(); 
} 

@Override 
public void onConnected(Bundle bundle) { 

    mLocationRequest = new LocationRequest(); 
    mLocationRequest.setInterval(1000); 
    mLocationRequest.setFastestInterval(1000); 
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 
    locationListenerFinder = new LocationListenerFinder(this); 
    if (locationPermission) { 
     LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, locationListenerFinder); 
    } 
} 

@Override 
public void onConnectionSuspended(int i) { 
    mLocationRequest = null; 
} 

@Override 
public void onLocationChanged(Location location) { 

    mLastLocation = location; 
    if (mCurrLocationMarker != null) { 
     mCurrLocationMarker.remove(); 
    } 
    int size = listNearByFacility.get(0).getNearBy().get(facilityPosition).getLocations().size(); 
    ivMyLocation.setVisibility(View.VISIBLE); 

    //Place current location marker 
    LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); 
    MarkerOptions markerOptions = new MarkerOptions(); 
    markerOptions.position(latLng); 
    markerOptions.icon(BitmapDescriptorFactory.fromBitmap(getBitmapMarker("Current Location", R.drawable.ic_marker_blue))); 

    //MarkerOptions markerOptions = new MarkerOptions(); 
    //markerOptions.videoPlayPosition(latLng); 
    //markerOptions.title("Current Location"); 
    //markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)); 
    mCurrLocationMarker = mMap.addMarker(markerOptions); 
    mCurrLocationMarker.setTag(size + 1); 

    //move map camera 
    // mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); 
    //mMap.animateCamera(CameraUpdateFactory.zoomTo(11)); 

    if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) { 
     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, locationListenerFinder); 
     mGoogleApiClient.disconnect(); 
     mGoogleApiClient.unregisterConnectionCallbacks(this); 
     mGoogleApiClient.unregisterConnectionFailedListener(this); 
     //locationListener.clearData(); 
     mLocationRequest = null; 
     locationListenerFinder = null; 
    } 
    mGoogleApiClient = null; 
} 

@Override 
public void onConnectionFailed(ConnectionResult connectionResult) { 

} 

public void checkLocationPermission() { 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
     if (!Utility.isPermissionAllowed(this, Manifest.permission.ACCESS_FINE_LOCATION)) { 
      Utility.showPermissionDialog(this, Manifest.permission.ACCESS_FINE_LOCATION, BookingKARConstants.PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION); 
      locationPermission = false; 
      return; 
     } else { 
      locationPermission = true; 
      return; 
     } 
    } 
    locationPermission = true; 
} 

@Override 
public void onRequestPermissionsResult(int requestCode, 
             String permissions[], int[] grantResults) { 
    //Checking the request code of our request 
    if (requestCode == BookingKARConstants.PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION) { 
     // If request is cancelled, the result arrays are empty. 
     if (grantResults.length > 0 
       && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 

      // permission was granted. Do the 
      locationPermission = true; 
      if (mGoogleApiClient == null) { 
       buildGoogleApiClient(); 
       checkLocationStatus(); 
      } 
      loadMap(); 
      //mMap.setMyLocationEnabled(true); 
     } else { 

      // Permission denied, Disable the functionality that depends on this permission. 
      Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show(); 
      finish(); 
     } 
     return; 
    } 

    // other 'case' lines to check for other permissions this app might request. 
    // You can add here other case statements according to your requirement. 
} 

private void checkLocationStatus() { 
    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
    boolean gps_enabled = false; 
    boolean network_enabled = false; 

    try { 
     gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER); 
    } catch (Exception ex) { 
    } 

    try { 
     network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 
    } catch (Exception ex) { 
    } 

    if (!gps_enabled && !network_enabled) { 
     // notify user 
     AlertDialog.Builder dialog = new AlertDialog.Builder(this); 
     dialog.setMessage(getResources().getString(R.string.gps_network_not_enabled)); 
     dialog.setPositiveButton(getResources().getString(R.string.open_location_settings), new DialogInterface.OnClickListener() { 
      @Override 
      public void onClick(DialogInterface paramDialogInterface, int paramInt) { 
       // TODO Auto-generated method stub 
       Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 
       startActivity(myIntent); 
       //get gps 
      } 
     }); 
     dialog.setNegativeButton(getString(R.string.Cancel), new DialogInterface.OnClickListener() { 

      @Override 
      public void onClick(DialogInterface paramDialogInterface, int paramInt) { 
       // TODO Auto-generated method stub 

      } 
     }); 
     dialog.show(); 
    } 
} 

/*class WeakLocationListener implements LocationListener { 

    private final WeakReference<LocationListener> locationListenerRef; 

    public WeakLocationListener(@NonNull LocationListener locationListener) { 
     locationListenerRef = new WeakReference<>(WeakLocationListener.this); 
    } 

    @Override 
    public void onLocationChanged(android.location.Location location) { 
     if (locationListenerRef.get() == null) { 
      return; 
     } 
     locationListenerRef.get().onLocationChanged(location); 
    } 

    public interface onLocationChanged { 
     void onLocationChanged(Location location); 
    } 

    public void clearData() { 
     if (locationListenerRef.get() != null) { 
      locationListenerRef.clear(); 
     } 
    }*/ 

//} 

}

+0

Ответ обновлен в феврале 2018 года, но не заметил, что LocationListener теперь устарел (с Google Play Services 11) – SimonH

1

Я имел утечку памяти, используя все эти предложения. Я заставил их остановиться, применив этот метод в тот момент, когда мне больше не нужен слушатель, к onDestroy и onStop. Я также добавил его в onPause, но вам нужно будет решить, подходит ли это для вашего приложения.

private void stopLocationListener() { 
    if (locationManager !=null) locationManager.removeUpdates(locationListener); 
    if (locationManager !=null) locationManager =null; 
    if (locationListener !=null) locationListener =null; 
} 
Смежные вопросы