Mal rendimiento de Google Maps Android y retraso en el mapa de la pantalla al dibujar una polilínea

14 minutos de lectura

Avatar de usuario de Emmanuel Molina
Emanuel Molina

Estoy desarrollando una aplicación que cumple la función de hacer una búsqueda de ruta, el usuario ingresa el punto de origen y destino, luego de esto a través de switch widget el usuario puede dibujar las rutas del resultado.

La interfaz y el mapa son fluidos, el problema ocurre cuando se dibuja 1 polilínea.

Estoy usando asynctask para cargar los datos de las coordenadas de las rutas y dibujarlas.

Para obtener las coordenadas, uso Android Maps Utils para decodificar y simplificar la polilínea. Cada polilínea contiene alrededor de 300 puntos y en total hay 40 polilíneas.

También uso un servicio para procesar los resultados de la búsqueda, funciona bien.

¿Qué más puedo hacer para optimizar esta carga de polilínea? He investigado pero los resultados son similares a lo que ya estoy haciendo.

¡Espero tu ayuda!

Código:

MapDemoActivity.class

public class MapDemoActivity extends AppCompatActivity
    implements
    GoogleMap.OnMyLocationButtonClickListener,
    GoogleMap.OnMyLocationClickListener {

private SupportMapFragment mapFragment;
public static GoogleMap map;
Location mCurrentLocation;
private final static String KEY_LOCATION = "location";
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
protected static final String TAG = "LocationOnOff";
private GoogleApiClient googleApiClient;
final static int REQUEST_LOCATION = 199;
public static final String EXTRA_CIRCULAR_REVEAL_X = "EXTRA_CIRCULAR_REVEAL_X";
public static final String EXTRA_CIRCULAR_REVEAL_Y = "EXTRA_CIRCULAR_REVEAL_Y";
View rootLayout;
private int revealX;
private int revealY;
FloatingActionButton searchButton, checkButton, checkButtonDestino, reset;
ImageView markerOrigen;
private RoundedView mRoundedIndicatorOrigin;
private RoundedView mRoundedIndicatorDestination;
TextView source_location, destination_location;
String type = "";
Intent intentAnim = null;
private GoogleMap.OnCameraIdleListener onCameraIdleListener;
Marker source_location_marker, destination_location_marker;
double LatOrigen;
double LonOrigen;
double LatDestino;
double LonDestino;
private SlidingUpPanelLayout mLayout;
SlidingUpPanelLayout dragView;
ArrayList<Integer> validadorFinal = new ArrayList<Integer>();
ArrayList<Switch> listSwitch = new ArrayList<Switch>();
private static final PatternItem DOT = new Dot();
private static final int PATTERN_DASH_LENGTH_PX = 50;
private static final PatternItem DASH = new Dash(PATTERN_DASH_LENGTH_PX);
private static final int PATTERN_GAP_LENGTH_PX = 10;
private static final PatternItem GAP = new Gap(PATTERN_GAP_LENGTH_PX);
private static final List<PatternItem> PATTERN_POLYLINE_DOTTED = Arrays.asList(DASH, DOT, GAP);


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.map_demo_activity);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeAsUpIndicator(R.drawable.arrow_left);

    LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mMessageFilterResult, new IntentFilter("validador"));


    intentAnim = getIntent();

    rootLayout = findViewById(R.id.root_layout);
    if (savedInstanceState == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
            intentAnim.hasExtra(EXTRA_CIRCULAR_REVEAL_X) &&
            intentAnim.hasExtra(EXTRA_CIRCULAR_REVEAL_Y)) {
        startAnim();
    }

    if (TextUtils.isEmpty(getResources().getString(R.string.google_maps_api_key))) {
        throw new IllegalStateException("You forgot to supply a Google Maps API key");
    }



    mapFragment = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
    if (mapFragment != null) {
        mapFragment.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap map) {
                loadMap(map);
            }
        });
    } else {
        Toast.makeText(this, "Error - Map Fragment was null!!", Toast.LENGTH_SHORT).show();
    }

    initView();

}

protected void startAnim(){
    rootLayout.setVisibility(View.INVISIBLE);

    revealX = intentAnim.getIntExtra(EXTRA_CIRCULAR_REVEAL_X, 0);
    revealY = intentAnim.getIntExtra(EXTRA_CIRCULAR_REVEAL_Y, 0);


    ViewTreeObserver viewTreeObserver = rootLayout.getViewTreeObserver();
    if (viewTreeObserver.isAlive()) {
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                revealActivity(revealX, revealY);
                rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });


    } else {
        rootLayout.setVisibility(View.VISIBLE);
    }
}


public void initView(){
    searchButton = (FloatingActionButton)findViewById(R.id.fab);
    //dataResultView.setVisibility(View.VISIBLE);
    markerOrigen = (ImageView)findViewById(R.id.markerTarget);
    dragView = (SlidingUpPanelLayout) findViewById(R.id.sliding_layout);
    checkButton = (FloatingActionButton)findViewById(R.id.fab2);
    checkButtonDestino = (FloatingActionButton)findViewById(R.id.fab3);

    reset = (FloatingActionButton) findViewById(R.id.reset);
    resetMap();


    mRoundedIndicatorOrigin = (RoundedView)findViewById(R.id.rounded_indicator_source);
    mRoundedIndicatorDestination = (RoundedView)findViewById(R.id.rounded_indicator_destination);


    source_location=(TextView) findViewById(R.id.source_location);
    source_location.setTag(0);
    destination_location=(TextView)findViewById(R.id.destination_location);
    destination_location.setTag(0);


    searchButton.setTag("1");
    searchOptions();


    mLayout = (SlidingUpPanelLayout) findViewById(R.id.sliding_layout);
    mLayout.setAnchorPoint(0.7f);
    //mLayout.setPanelState(SlidingUpPanelLayout.PanelState.ANCHORED);
    mLayout.addPanelSlideListener(new SlidingUpPanelLayout.PanelSlideListener() {
        @Override
        public void onPanelSlide(View panel, float slideOffset) {
            Log.i(TAG, "onPanelSlide, offset " + slideOffset);
        }

        @Override
        public void onPanelStateChanged(View panel, SlidingUpPanelLayout.PanelState previousState, SlidingUpPanelLayout.PanelState newState) {
            Log.i(TAG, "onPanelStateChanged " + newState);
        }
    });
    mLayout.setFadeOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //mLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
            mLayout.setAnchorPoint(0.7f);
            mLayout.setPanelState(SlidingUpPanelLayout.PanelState.ANCHORED);
        }
    });
}

private void resetMap(){
    reset.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            map.clear();
            map.setOnCameraIdleListener(null);
            source_location.setText(null);
            destination_location.setText(null);
            mRoundedIndicatorOrigin.setChecked(false);
            mRoundedIndicatorDestination.setChecked(false);
            searchButton.setTag("1");
            type="";


            if (listSwitch.isEmpty()) {
                //Nothing
            }else {
                for (int i=0; i <= 79; i++) {
                    if (listSwitch.get(i).isChecked()) {
                        listSwitch.get(i).setChecked(false);
                    }
                }
            }

            searchButton.hide();
            checkButtonDestino.hide();
            checkButton.hide();
            reset.hide();
            dragView.setPanelHeight(0);
        }
    });
}

private void searchOptions() {
    source_location.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            configureCameraIdle();
            mRoundedIndicatorOrigin.setChecked(true);
            mRoundedIndicatorDestination.setChecked(false);
            map.setOnCameraIdleListener(onCameraIdleListener);

            checkButton.show();

            markerOrigen.setVisibility(View.VISIBLE);
        }
    });

    destination_location.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            configureCameraIdle2();
            mRoundedIndicatorOrigin.setChecked(false);
            mRoundedIndicatorDestination.setChecked(true);
            map.setOnCameraIdleListener(onCameraIdleListener);
            checkButtonDestino.show();

            markerOrigen.setVisibility(View.VISIBLE);
        }
    });

}

private void configureCameraIdle() {
    getDataCameraIdle();
    onCameraIdleListener = new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
          getDataCameraIdle();
        }
    };
}

private void getDataCameraIdle(){
    LatLng latLng = map.getCameraPosition().target;
    Location mLocation = new Location("");
    mLocation.setLatitude(latLng.latitude);
    mLocation.setLongitude(latLng.longitude);

    new AsyncGeocoder().execute(new AsyncGeocoderObject(
            new Geocoder(this),
            mLocation,
            source_location
    ));


    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(latLng);
    markerOptions.title("Origen");

    checkButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkButton.setTag("1");
            map.setOnCameraIdleListener(null);
            //Log.d("TAG", "click checkbutton");
            if (source_location_marker!=null)
            {
                source_location_marker.remove();
            }
            LatOrigen = latLng.latitude;
            LonOrigen = latLng.longitude;
            source_location_marker=map.addMarker(markerOptions);
            markerOrigen.setVisibility(View.GONE);
            checkButton.hide();
            source_location.setTag(1);

            checkSearchButtonStatus();

        }
    });
}

private void configureCameraIdle2() {
    getDataCameraIdle2();
    onCameraIdleListener = new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
            getDataCameraIdle2();
        }
    };
}

private void getDataCameraIdle2(){
    LatLng latLng = map.getCameraPosition().target;
    Location mLocation = new Location("");
    mLocation.setLatitude(latLng.latitude);
    mLocation.setLongitude(latLng.longitude);

    new AsyncGeocoder().execute(new AsyncGeocoderObject(
            new Geocoder(this),
            mLocation,
            destination_location
    ));

    MarkerOptions markerOptions = new MarkerOptions();
    markerOptions.position(latLng);
    markerOptions.title("Destino");

    checkButtonDestino.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkButtonDestino.setTag("1");
            map.setOnCameraIdleListener(null);
            Log.d("TAG", "click checkbutton destino");
            if (destination_location_marker!=null)
            {
                destination_location_marker.remove();
            }
            LatDestino = latLng.latitude;
            LonDestino= latLng.longitude;
            destination_location_marker=map.addMarker(markerOptions);
            markerOrigen.setVisibility(View.GONE);
            checkButtonDestino.hide();
            destination_location.setTag("1");

            checkSearchButtonStatus();

        }
    });
}

private void checkSearchButtonStatus() {
    if(source_location.getTag()!=null && destination_location.getTag()!=null){
        type = source_location.getTag().toString() + destination_location.getTag().toString();
    }
    switch (type) {
        case "10":
            //Show toast polyline 1 ("A")
            Toast.makeText(getApplicationContext(), "Selecciona un destino", Toast.LENGTH_LONG).show();
            break;
        case "01":
            Toast.makeText(this, "Selecciona un origen", Toast.LENGTH_SHORT).show();
            break;
        case "11":
            initSearchService();
            searchButton.show();
            break;
    }
}

public void initSearchService(){
    searchButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(searchButton.getTag().toString()=="1"){
                Intent intent = new Intent(MapDemoActivity.this, searchService.class);
                intent.putExtra("LatOrigen",LatOrigen);
                intent.putExtra("LonOrigen",LonOrigen);
                intent.putExtra("LatDestino",LatDestino);
                intent.putExtra("LonDestino",LonDestino);
                startService(intent);

                int sizeInPixel = getApplicationContext().getResources().getDimensionPixelSize(R.dimen.dragView);
                dragView.setPanelHeight(sizeInPixel);

                source_location.setTag("0");
                destination_location.setTag("0");

                searchButton.setTag("0");
                searchButton.hide();
                reset.show();
            }else {

            }
        }
    });
}

protected void revealActivity(int x, int y) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            float finalRadius = (float) (Math.max(rootLayout.getWidth(), rootLayout.getHeight()) * 1.1);

            // create the animator for this view (the start radius is zero)
            Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootLayout, x, y, 0, finalRadius);
            circularReveal.setDuration(1190);
            circularReveal.setInterpolator(new AccelerateInterpolator());

            // make the view visible and start the animation
            rootLayout.setVisibility(View.VISIBLE);
            circularReveal.start();
        } else {
            finish();
        }
    }


@SuppressLint("MissingPermission")
protected void loadMap(GoogleMap googleMap) {
    map = googleMap;
    if (map != null) {
        // Map is ready
        map.setMyLocationEnabled(true);
        map.setOnMyLocationButtonClickListener(this);
        map.setOnMyLocationClickListener(this);
        changeGPSIcon();


        try {
            // Customise the styling of the base map using a JSON object defined
            // in a raw resource file.
            boolean success = map.setMapStyle(
                    MapStyleOptions.loadRawResourceStyle(
                            this, R.raw.style_json));

            if (!success) {
            }
        } catch (Resources.NotFoundException e) {

        }


        LatLng marker = new LatLng(19.407021,  -102.046595);
        map.moveCamera(CameraUpdateFactory.newLatLngZoom(marker, 13));
        //Zoom Preferences
        map.setMinZoomPreference(12);
        map.setMaxZoomPreference(19);
    } else {
        Toast.makeText(this, "Error - Map was null!!", Toast.LENGTH_SHORT).show();
    }
}

public void changeGPSIcon() {
    ImageView locationButton = (ImageView) mapFragment.getView().findViewById(Integer.parseInt("2"));
    locationButton.setVisibility(View.GONE);
    FloatingActionButton gpsButton = findViewById(R.id.gpsbutton);
    gpsButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            locationButton.callOnClick();
        }
    });
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    MapDemoActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);

    switch (requestCode) {
        case 0x1:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "Permission is granted", Toast.LENGTH_SHORT).show();
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
                    enableMyLocation();
            }

    }
}



private void enableMyLocation() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            // Permission to access the location is missing.
            PermissionUtils.requestPermission(this, LOCATION_PERMISSION_REQUEST_CODE,
                    Manifest.permission.ACCESS_FINE_LOCATION, true);
        } else if (map != null) {
            // Access to the location has been granted to the app.
            map.setMyLocationEnabled(true);
        }
    }

    @Override
    public boolean onMyLocationButtonClick() {
        enableLoc();
        return false;
    }

    @Override
    public void onMyLocationClick(@NonNull Location location) {
        Toast.makeText(this, "Ubicación actual", Toast.LENGTH_LONG).show();
    }


public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putParcelable(KEY_LOCATION, mCurrentLocation);
    super.onSaveInstanceState(savedInstanceState);
}

private void enableLoc() {

    if (googleApiClient == null) {
        googleApiClient = new GoogleApiClient.Builder(MapDemoActivity.this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(Bundle bundle) {

                    }

                    @Override
                    public void onConnectionSuspended(int i) {
                        googleApiClient.connect();
                    }
                })
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(ConnectionResult connectionResult) {

                        Log.d("Location error", "Location error " + connectionResult.getErrorCode());
                    }
                }).build();
        googleApiClient.connect();

        LocationRequest locationRequest = LocationRequest.create();
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setInterval(30 * 1000);
        locationRequest.setFastestInterval(5 * 1000);
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(locationRequest);

        builder.setAlwaysShow(true);

        PendingResult<LocationSettingsResult> result =
                LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
        result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
            @Override
            public void onResult(LocationSettingsResult result) {
                final Status status = result.getStatus();
                switch (status.getStatusCode()) {
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        try {
                            // Show the dialog by calling startResolutionForResult(),
                            // and check the result in onActivityResult().
                            status.startResolutionForResult(MapDemoActivity.this, REQUEST_LOCATION);

                            //finish();
                        } catch (IntentSender.SendIntentException e) {
                            // Ignore the error.
                        }
                        break;
                }
            }
        });
    }
}


@Override
public void onBackPressed() {
    if (mLayout != null &&
            (mLayout.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED || mLayout.getPanelState() == SlidingUpPanelLayout.PanelState.ANCHORED)) {
        mLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
    } else {
        super.onBackPressed();
    }
}



private BroadcastReceiver mMessageFilterResult = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getBundleExtra("extra");
        if (bundle != null) {
            validadorFinal = (ArrayList<Integer>) bundle.getIntegerArrayList("validadorFinal_");
        } else {
        }
        new polylinePrinter().execute();
    }
};


protected class polylinePrinter extends AsyncTask {

    PolylineOptions pUnidad1PalitoVerdeIda;
    PolylineOptions pUnidad1PalitoVerdeVuelta;

    PolylineOptions pUnidad1ManantialesIda;
    PolylineOptions pUnidad1ManantialesVuelta;

    PolylineOptions pUnidad1SanJoseIda;
    PolylineOptions pUnidad1SanJoseVuelta;

    PolylineOptions pConstiZumpi2AIda;
    PolylineOptions pConstiZumpi2AVuelta;

    PolylineOptions pConstiJica2Ida;
    PolylineOptions pConstiJica2Vuelta;



    List<LatLng> simplifydecodedRuta1Ida;
    List<LatLng> simplifydecodedRuta1Vuelta;


    List<LatLng> simplifydecodedRuta1MIda;
    List<LatLng> simplifydecodedRuta1MVuelta;

    List<LatLng> simplifydecodedRuta1SIda;
    List<LatLng> simplifydecodedRuta1SVuelta;

    List<LatLng> simplifydecodedRuta3Ida;
    List<LatLng> simplifydecodedRuta3Vuelta;

    List<LatLng> simplifydecodedRuta5Ida;
    List<LatLng> simplifydecodedRuta5Vuelta;

    @Override
    protected Object doInBackground(Object[] objects) {
        double tolerance = 20;

        if (validadorFinal.get(0)==1){
            simplifydecodedRuta1Ida = PolyUtil.simplify(ConstantsRoutes.decodedRuta1Ida, tolerance);
            simplifydecodedRuta1Vuelta = PolyUtil.simplify(ConstantsRoutes.decodedRuta1Vuelta, tolerance);
            Loader1Ida();
            Loader1Vuelta();
        }

        if (validadorFinal.get(1)==1){
            simplifydecodedRuta1MIda = PolyUtil.simplify(ConstantsRoutes.decodedRuta1MIda, tolerance);
            simplifydecodedRuta1MVuelta = PolyUtil.simplify(ConstantsRoutes.decodedRuta1MVuelta, tolerance);
            Loader1MIda();
            Loader1MVuelta();
        }

        if (validadorFinal.get(2)==1){
            simplifydecodedRuta1SIda = PolyUtil.simplify(ConstantsRoutes.decodedRuta1SIda, tolerance);
            simplifydecodedRuta1SVuelta = PolyUtil.simplify(ConstantsRoutes.decodedRuta1SVuelta, tolerance);
            Loader1SIda();
            Loader1SVuelta();
        }

        if (validadorFinal.get(3)==1){
            simplifydecodedRuta2Ida = PolyUtil.simplify(ConstantsRoutes.decodedRuta2Ida, tolerance);
            simplifydecodedRuta2Vuelta = PolyUtil.simplify(ConstantsRoutes.decodedRuta2Vuelta, tolerance);
            Loader2Ida();
            Loader2Vuelta();
        }

        if (validadorFinal.get(4)==1){
            Loader2AIda();
            Loader2AVuelta();
        }

        if (validadorFinal.get(5)==1){
            simplifydecodedRuta3Ida = PolyUtil.simplify(ConstantsRoutes.decodedRuta3Ida, tolerance);
            simplifydecodedRuta3Vuelta = PolyUtil.simplify(ConstantsRoutes.decodedRuta3Vuelta, tolerance);
            Loader3Ida();
            Loader3Vuelta();
        }

        return null;
    }

    protected void onPostExecute(Object result) {
        loadSwitches();
        if(validadorFinal.get(0)==1){
           shower1Vuelta();
            Shower1Ida();
        }

        if (validadorFinal.get(1)==1){
            shower1MIda();
            shower1MVuelta();
        }

        if (validadorFinal.get(2)==1){
            shower1SIda();
            shower1SVuelta();
        }

        if (validadorFinal.get(3)==1){
            shower2Ida();
            shower2Vuelta();
        }

        if (validadorFinal.get(4)==1){
            shower2AIda();
            shower2AVuelta();
        }

        if (validadorFinal.get(5)==1){
            shower3Ida();
            shower3Vuelta();
        }
    }


    private void loadSwitches(){
        Switch switch_ida1 = (Switch) findViewById(R.id.switchIdaRuta1);
        Switch switch_vuelta1 = (Switch) findViewById(R.id.switchVueltaRuta1);

        Switch switch_ida1M = (Switch) findViewById(R.id.switchIdaRuta1M);
        Switch switch_vuelta1M = (Switch) findViewById(R.id.switchVueltaRuta1M);

        Switch switch_ida1S = (Switch) findViewById(R.id.switchIdaRuta1S);
        Switch switch_vuelta1S = (Switch) findViewById(R.id.switchVueltaRuta1S);

        Switch switch_ida2A = (Switch) findViewById(R.id.switchIdaRuta2A);
        Switch switch_vuelta2A = (Switch) findViewById(R.id.switchVueltaRuta2A);

        Switch switch_ida2 = (Switch) findViewById(R.id.switchIdaRuta2);
        Switch switch_vuelta2 = (Switch) findViewById(R.id.switchVueltaRuta2);

        Switch switch_ida3 = (Switch) findViewById(R.id.switchIdaRuta3);
        Switch switch_vuelta3 = (Switch) findViewById(R.id.switchVueltaRuta3);

        Switch switch_ida4 = (Switch) findViewById(R.id.switchIdaRuta4);
        Switch switch_vuelta4 = (Switch) findViewById(R.id.switchVueltaRuta4);

        Switch switch_ida5 = (Switch) findViewById(R.id.switchIdaRuta5);
        Switch switch_vuelta5 = (Switch) findViewById(R.id.switchVueltaRuta5);

        listSwitch.add(0,switch_ida1);
        listSwitch.add(1, switch_vuelta1);

        listSwitch.add(2,switch_ida1M);
        listSwitch.add(3,switch_vuelta1M);

        listSwitch.add(4,switch_ida1S);
        listSwitch.add(5,switch_vuelta1S);
    }


    private void Loader1Ida(){
        pUnidad1PalitoVerdeIda = new PolylineOptions();
        pUnidad1PalitoVerdeIda.addAll(simplifydecodedRuta1Ida)
                .color(Color.parseColor("#2196F3")); //Color blue
    }
    private void Shower1Ida(){
        LinearLayout linearLayout1 = (LinearLayout) findViewById(R.id.layoutRuta1);
        linearLayout1.setVisibility(View.VISIBLE);

        final Polyline[] Unidad1PalitoVerdeIda = new Polyline[1];
        listSwitch.get(0).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {

                    Unidad1PalitoVerdeIda[0] = map.addPolyline(pUnidad1PalitoVerdeIda);
                    Unidad1PalitoVerdeIda[0].setClickable(true);
                    Unidad1PalitoVerdeIda[0].setTag("Unidad1PalitoVerdeIda");
                    Unidad1PalitoVerdeIda[0].setWidth(8);
                    Unidad1PalitoVerdeIda[0].setPattern(PATTERN_POLYLINE_DOTTED);
                } else {
                    Unidad1PalitoVerdeIda[0].remove();
                }
            }
        });
   //39 Routes more 

}

Avatar de usuario de Andrii Omelchenko
andrii omelchenko

Puede reducir el retraso del mapa de pantalla al dibujar polilíneas si no dibuja todas, sino solo generaliza para cada nivel de zoom “especial” (punto donde cambia la ruta) punto de sus polilíneas. Para determinar puntos “especiales” de su ruta puede usar, por ejemplo, Algoritmo Ramer-Douglas-Peucker:

Simplificación del camino Ramer-Douglas-Peucker

Puedes usar Biblioteca de utilidades de la API de Android de Google Maps especialmente
PolyUtil.simplify() método como su implementación.

También, aquí puede encontrar su implementación en Java (con comentarios):

private static class Point extends Pair<Double, Double> {
    Point(Double key, Double value) {
        super(key, value);
    }

    @Override
    public String toString() {
        return String.format("(%f, %f)", getKey(), getValue());
    }
}

private static double perpendicularDistance(Point pt, Point lineStart, Point lineEnd) {
    double dx = lineEnd.getKey() - lineStart.getKey();
    double dy = lineEnd.getValue() - lineStart.getValue();

    // Normalize
    double mag = Math.hypot(dx, dy);
    if (mag > 0.0) {
        dx /= mag;
        dy /= mag;
    }
    double pvx = pt.getKey() - lineStart.getKey();
    double pvy = pt.getValue() - lineStart.getValue();

    // Get dot product (project pv onto normalized direction)
    double pvdot = dx * pvx + dy * pvy;

    // Scale line direction vector and subtract it from pv
    double ax = pvx - pvdot * dx;
    double ay = pvy - pvdot * dy;

    return Math.hypot(ax, ay);
}

private static void ramerDouglasPeucker(List<Point> pointList, double epsilon, List<Point> out) {
    if (pointList.size() < 2) throw new IllegalArgumentException("Not enough points to simplify");

    // Find the point with the maximum distance from line between the start and end
    double dmax = 0.0;
    int index = 0;
    int end = pointList.size() - 1;
    for (int i = 1; i < end; ++i) {
        double d = perpendicularDistance(pointList.get(i), pointList.get(0), pointList.get(end));
        if (d > dmax) {
            index = i;
            dmax = d;
        }
    }

    // If max distance is greater than epsilon, recursively simplify
    if (dmax > epsilon) {
        List<Point> recResults1 = new ArrayList<>();
        List<Point> recResults2 = new ArrayList<>();
        List<Point> firstLine = pointList.subList(0, index + 1);
        List<Point> lastLine = pointList.subList(index, pointList.size());
        ramerDouglasPeucker(firstLine, epsilon, recResults1);
        ramerDouglasPeucker(lastLine, epsilon, recResults2);

        // build the result list
        out.addAll(recResults1.subList(0, recResults1.size() - 1));
        out.addAll(recResults2);
        if (out.size() < 2) throw new RuntimeException("Problem assembling output");
    } else {
        // Just return start and end points
        out.clear();
        out.add(pointList.get(0));
        out.add(pointList.get(pointList.size() - 1));
    }
}

cambio de double epsilon puede crear listas reducidas de puntos de ruta “generalizados” para cada nivel de zoom y reducir el retraso del mapa.

  • Usé PolyUtil.siplify() pero en la documentación dice: “La complejidad temporal de Douglas-Peucker es O(n^2), así que tenga cuidado de no llamar a este algoritmo con demasiada frecuencia en su código”. Lo llamé tal vez 20 veces y el mapa sigue retrasado

    –Emanuel Molina

    23 de agosto de 2019 a las 20:41

  • @EmmanuelMolina necesitas usar PolyUtil.siplify() solo una vez justo después de descargar los datos de sus polilíneas. Luego almacene datos de polilínea simplificados y utilícelos. En realidad, no una vez, sino una vez para cada nivel de zoom: por ejemplo, para el nivel de zoom 20 use una polilínea no simplificada, para el nivel de zoom 19 – use PolyUtil.siplify() con tolearnce1para el nivel de zoom 19 – utilice PolyUtil.siplify() con tolearnce2, tolearnce2 > tolearnce1 etc. Quiero decir: precalcule polilíneas para cada nivel de zoom (o una polilínea simplificada para varios niveles de zoom) y use una vez los datos precalculados. O(n^2) es apropiado para ese caso.

    –Andrii Omelchenko

    24 de agosto de 2019 a las 6:39

¿Ha sido útil esta solución?