首页 > 解决方案 > 绘制折线时Google Maps Android性能不佳和屏幕地图滞后

问题描述

我正在开发一个实现路线搜索功能的应用程序,用户输入起点和目的地,然后通过切换小部件用户可以绘制结果的路线。

界面和地图是流畅的,绘制1条折线时会出现问题。

我正在使用 asynctask 加载路线坐标的数据并绘制它们。

为了获得坐标,我使用 Android Maps Utils 来解码和简化折线。每条折线包含大约 300 个点,总共有 40 条折线。

我还使用服务来处理搜索结果,效果很好。

我还能做些什么来优化这个折线负载?我进行了研究,但结果与我已经在做的相似。

我期待您的帮助!

代码:

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 

}

标签: javaandroidperformancegoogle-mapsgoogle-polyline

解决方案


如果您绘制的不是全部,而是仅针对折线的每个缩放级别“特殊”(路径更改的点)点进行概括,则可以减少绘制折线时的屏幕地图滞后。为了确定路径的“特殊”点,您可以使用例如Ramer-Douglas-Peucker 算法

Ramer-Douglas-Peucker 路径简化

您可以使用Google Maps Android API Utility Library特别是 PolyUtil.simplify()方法作为其实现。

此外,在这里您可以找到它在 Java 中的实现(带注释):

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));
    }
}

更改double epsilon值,您可以为每个缩放级别创建简化的“通用”路径点列表并减少地图滞后。


推荐阅读