【问题标题】:Directions API Crashes the Application on Smartphone and BlueStacks but Not on Android Studio EmulatorDirections API 在智能手机和 BlueStacks 上使应用程序崩溃,但在 Android Studio 模拟器上却没有
【发布时间】:2020-05-13 00:37:05
【问题描述】:

我正在使用用于 Google Maps API Web 服务的 Java 客户端库在两点之间绘制路线。它在 Android Studio 的模拟器上运行良好,但在 Blue Stack 和我的智能手机上崩溃。

我从项目模板创建了 Maps Activity,只编辑了 AppGradle 和 MapsActivity。应用可以按预期正常运行,但只能在 Android Studio 的模拟器上运行。

这是 Android Studio Emulator(Android 10) 中的工作图像 enter image description here

所以应用程序在这一行崩溃(到目前为止我发现了什么): --directions.destination(destination).setCallback(new PendingResult.Callback() {

这是我的 MapsActivity:

公共类 MapsActivity 扩展 FragmentActivity 实现 OnMapReadyCallback {

private static final String TAG = "TaG";
private GoogleMap mMap;
static final int REQUEST_LOCATION_PERMISSION = 99;
double mUserlatitude, mUserlongitude;
ArrayList<PolylineData> mPolyLinesData = new ArrayList<>();
Marker marker =null;
GeoApiContext mGeoApiContext;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    mGeoApiContext = new GeoApiContext.Builder().apiKey("google_maps_api_key").build();
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}


/**
 * 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;
    enableMyLocation();

    mMap.getUiSettings().setZoomControlsEnabled(true);

    // Add a marker in Sydney and move the camera
    LatLng sydney = new LatLng(31.522738, 74.358556);
    marker = mMap.addMarker(new MarkerOptions().position(sydney));
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 12));

    mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
        @Override
        public boolean onMarkerClick(Marker marker) {
            LatLng start = new LatLng(mUserlatitude,mUserlongitude);
            calculateDirections(start,marker);
            return false;
        }
    });

}

private void enableMyLocation() {
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {
        mMap.setMyLocationEnabled(true);
        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, locationListener);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 0, locationListener);
    } else {
        ActivityCompat.requestPermissions(this, new String[]
                        {Manifest.permission.ACCESS_FINE_LOCATION},
                REQUEST_LOCATION_PERMISSION);
    }
}



@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    // Check if location permissions are granted and if so enable the
    // location data layer.
    switch (requestCode) {
        case REQUEST_LOCATION_PERMISSION:
            if (grantResults.length > 0
                    && grantResults[0]
                    == PackageManager.PERMISSION_GRANTED) {
                enableMyLocation();

            }else{
                enableMyLocation();
            }
            break;
    }
}

LocationListener locationListener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
        mUserlatitude = location.getLatitude();
        mUserlongitude = location.getLongitude();
        //Toast.makeText(MapsActivity.this, Double.toString(mUserlatitude), Toast.LENGTH_SHORT).show();
        //Toast.makeText(MapsActivity.this, marker.getPosition().toString(), Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {
    }
    @Override
    public void onProviderEnabled(String s) {
    }
    @Override
    public void onProviderDisabled(String s) {
    }
};



private void calculateDirections(LatLng start, Marker marker){
    Log.d(TAG, "calculateDirections: calculating directions.");

    com.google.maps.model.LatLng destination = new com.google.maps.model.LatLng(
            marker.getPosition().latitude,
            marker.getPosition().longitude
    );
    DirectionsApiRequest directions = new DirectionsApiRequest(mGeoApiContext);

    directions.alternatives(true);
    directions.origin(
            new com.google.maps.model.LatLng(
                    start.latitude,start.longitude
            )
    );
    //Log.d(TAG, "calculateDirections: destination: " + destination.toString());
    directions.destination(destination).setCallback(new PendingResult.Callback<DirectionsResult>() {
        @Override
        public void onResult(DirectionsResult result) {
            Log.d(TAG, "calculateDirections: routes: " + result.routes[0].toString());
            Log.d(TAG, "calculateDirections: duration: " + result.routes[0].legs[0].duration);
            Log.d(TAG, "calculateDirections: distance: " + result.routes[0].legs[0].distance);
            Log.d(TAG, "calculateDirections: geocodedWayPoints: " + result.geocodedWaypoints[0].toString());

            addPolylinesToMap(result);
        }

        @Override
        public void onFailure(Throwable e) {
            Log.e(TAG, "calculateDirections: Failed to get directions: " + e.getMessage() );
            return;
        }
    });
}



private void addPolylinesToMap(final DirectionsResult result){
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {


            if(mPolyLinesData.size() > 0){
                for(PolylineData polylineData: mPolyLinesData){
                    polylineData.getPolyline().remove();
                }
                mPolyLinesData.clear();
                mPolyLinesData = new ArrayList<>();
            }
            double firstduration = 0;
            for(DirectionsRoute route: result.routes){

                List<com.google.maps.model.LatLng> decodedPath = PolylineEncoding.decode(route.overviewPolyline.getEncodedPath());

                List<LatLng> newDecodedPath = new ArrayList<>();

                // This loops through all the LatLng coordinates of ONE polyline.
                for(com.google.maps.model.LatLng latLng: decodedPath){

                    Log.d(TAG, "run: latlng: " + latLng.toString());

                    newDecodedPath.add(new LatLng(
                            latLng.lat,
                            latLng.lng
                    ));
                }
                Polyline polyline = mMap.addPolyline(new PolylineOptions().addAll(newDecodedPath));
                polyline.setColor(ContextCompat.getColor(getApplicationContext(), R.color.quantum_grey));
                polyline.setClickable(true);
                mPolyLinesData.add(new PolylineData(polyline, route.legs[0]));



                double thisduration = route.legs[0].duration.inSeconds;
                if(firstduration == 0) {
                    firstduration= thisduration;
                    onPolylineClickListener.onPolylineClick(polyline);
                }
                if(thisduration < firstduration){
                    firstduration = thisduration;
                    onPolylineClickListener.onPolylineClick(polyline);
                }
                if(result.routes.length == 1) onPolylineClickListener.onPolylineClick(polyline);



            }
        }
    });
}

GoogleMap.OnPolylineClickListener onPolylineClickListener = new GoogleMap.OnPolylineClickListener() {
    @Override
    public void onPolylineClick(Polyline polyline) {

        int index = 0;
        for(PolylineData polylineData: mPolyLinesData){
            index++;
            //Log.d(TAG, "onPolylineClick: toString: " + polylineData.toString());
            if(polyline.getId().equals(polylineData.getPolyline().getId())){
                polylineData.getPolyline().setColor(ContextCompat.getColor(getApplicationContext(), R.color.quantum_lightblue));
                polylineData.getPolyline().setZIndex(1);

                if(marker != null)marker.remove();
                LatLng endlocation = new LatLng(polylineData.getLeg().endLocation.lat, polylineData.getLeg().endLocation.lng);
                marker = mMap.addMarker(new MarkerOptions().position(endlocation).title("Trip # "+ index).snippet("Duration: "+polylineData.getLeg().duration));
                marker.showInfoWindow();
                zoomRoute(polyline.getPoints());
            }
            else{
                polylineData.getPolyline().setColor(ContextCompat.getColor(getApplicationContext(), R.color.quantum_grey));
                polylineData.getPolyline().setZIndex(0);
            }
        }
    }
};

public void zoomRoute(List<LatLng> lstLatLngRoute) {

    if (mMap == null || lstLatLngRoute == null || lstLatLngRoute.isEmpty()) return;

    LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
    for (LatLng latLngPoint : lstLatLngRoute)
        boundsBuilder.include(latLngPoint);

    int routePadding = 120;
    LatLngBounds latLngBounds = boundsBuilder.build();

    mMap.animateCamera(
            CameraUpdateFactory.newLatLngBounds(latLngBounds, routePadding),
            600,
            null
    );
}


public static class PolylineData {

    private Polyline polyline;
    private DirectionsLeg leg;

    public PolylineData(Polyline polyline, DirectionsLeg leg) {
        this.polyline = polyline;
        this.leg = leg;
    }

    public Polyline getPolyline() {
        return polyline;
    }

    public void setPolyline(Polyline polyline) {
        this.polyline = polyline;
    }

    public DirectionsLeg getLeg() {
        return leg;
    }

    public void setLeg(DirectionsLeg leg) {
        this.leg = leg;
    }

    @Override
    public String toString() {
        return "PolylineData{" +
                "polyline=" + polyline +
                ", leg=" + leg +
                '}';
    }
}

}

下面是 App Gradle:

应用插件:'com.android.application' 应用插件:'com.google.gms.google-services'

机器人{ compileSdkVersion 29 buildToolsVersion "29.0.2"

defaultConfig {
    applicationId "com.example.myapplication"
    minSdkVersion 16
    targetSdkVersion 29
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
compileOptions {
    targetCompatibility = 1.8
    sourceCompatibility = 1.8
}

}

依赖{ 实现 fileTree(dir: 'libs', include: ['*.jar'])

implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.firebase:firebase-auth:19.3.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.google.maps:google-maps-services:0.13.0'
implementation 'org.slf4j:slf4j-simple:1.7.25'
implementation 'com.google.android.libraries.places:places:2.2.0'

}

【问题讨论】:

    标签: directions map-directions java-client


    【解决方案1】:

    这解决了我的问题。

    调试我的应用程序后,我发现将其添加到应用程序级 gradle 文件 (build.gradle(app)) 中的 dependencies 有助于解决问题。

    implementation group: 'com.github.seratch', name: 'java-time-backport', version: '1.0.0'
    

    【讨论】:

    • 请不要投反对票,由于我的声誉低,我无法对实际帖子发表评论。我将根据@Salman Butt 的输入删除/编辑我的答案
    • 最新的 BlueStacks 和我的智能手机 android 版本是 Lolipop (5.1)。我的 android 应用的最低 api 版本是 16。
    • 我在 Bluestakcs 上遇到了同样的问题。但它在我的带有 android 10.0 和 9.0 的手机上运行良好
    • 嘿@SalmanButt,更新了我的答案,请检查并告诉我是否有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    • 2019-10-19
    相关资源
    最近更新 更多