有一个问题,为什么我MainActivity中获取定位就那么顺利呢?package com.example.bus;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.example.bus.databinding.ActivityMainBinding;
import com.google.android.material.bottomnavigation.BottomNavigationView;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private static final String SAVED_NAV_ID = "saved_nav_id";
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ✅ 添加日志:查看冷启动时权限是否已被系统撤销
Log.d("PERMISSION_DEBUG", "onCreate: FINE_LOCATION_GRANTED = " +
(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED));
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
BottomNavigationView navView = findViewById(R.id.nav_view);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home,
R.id.navigation_map,
R.id.navigation_settings)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
// ✅ 更新底部导航逻辑
navView.setOnItemSelectedListener(item -> {
int itemId = item.getItemId();
if (itemId == R.id.navigation_map) {
ensureFineLocationPermission(() -> {
if (navController.getCurrentDestination().getId() != R.id.navigation_map) {
navController.navigate(R.id.navigation_map);
}
});
return true;
}
navController.navigate(itemId);
return true;
});
// 恢复上次选中的底部菜单项
if (savedInstanceState != null) {
int savedId = savedInstanceState.getInt(SAVED_NAV_ID, R.id.navigation_home);
navView.setSelectedItemId(savedId);
}
}
// ✅ 新增:通用权限保障方法(所有进地图前都必须走这里)
public void ensureFineLocationPermission(Runnable onGranted) {
boolean hasFine = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (hasFine) {
onGranted.run(); // 权限存在,直接执行
} else {
requestFineLocationPermission(onGranted); // 否则发起请求
}
}
/**
* 请求精确定位权限(带解释说明)
*/
private void requestFineLocationPermission(Runnable onGranted) {
boolean hasFine = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (hasFine) {
onGranted.run();
return;
}
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
new AlertDialog.Builder(this)
.setTitle("需要精确定位权限")
.setMessage("为了准确查找您附近的公交站点和车辆位置,本应用需要获取您的精确位置。\n否则将无法使用地图相关功能。\n\n请务必选择【允许】或【仅限这一次】。")
.setPositiveButton("去允许", (d, w) -> requestFineLocation())
.setNegativeButton("取消", null)
.show();
} else {
requestFineLocation();
}
}
private void requestFineLocation() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
LOCATION_PERMISSION_REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
boolean hasFine = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (hasFine) {
Toast.makeText(this, "已获得精确定位权限", Toast.LENGTH_SHORT).show();
navigateToMapIfNeeded();
} else {
boolean hasCoarse = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (hasCoarse) {
new AlertDialog.Builder(this)
.setTitle("需要精确位置")
.setMessage("检测到您使用的是【大致位置】,这会导致地图功能无法正常使用。\n\n" +
"请在设置中将定位权限修改为【精确位置】。")
.setPositiveButton("去设置", (d, w) -> openAppSettings())
.setNegativeButton("取消", null)
.show();
} else {
Toast.makeText(this, "定位权限未授予,无法使用地图功能", Toast.LENGTH_LONG).show();
}
}
}
}
private void navigateToMapIfNeeded() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
if (navController.getCurrentDestination().getId() != R.id.navigation_map) {
navController.navigate(R.id.navigation_map);
}
}
private void openAppSettings() {
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
BottomNavigationView navView = findViewById(R.id.nav_view);
outState.putInt(SAVED_NAV_ID, navView.getSelectedItemId());
}
}
但是一到这边就报错package com.example.bus;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.route.*;
import com.amap.api.services.core.AMapException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.services.route.BusPath;
public class RoutePlanActivity extends AppCompatActivity implements RouteSearch.OnRouteSearchListener, AMapLocationListener {
// ✅ 来源类型常量
public static final String EXTRA_SOURCE = "extra_source";
public static final int SOURCE_FROM_HOME_SEARCH = 1001;
public static final int SOURCE_FROM_MAP_DIRECT = 1002;
private MapView mapView;
private AMap aMap;
private RouteSearch routeSearch;
private RecyclerView recyclerSteps;
private boolean isSearching = false;
private int sourceType = -1;
// ✅ 新增:定位客户端
private AMapLocationClient locationClient;
private LatLonPoint currentLocation; // 存储真实位置
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_route_plan);
// ✅ 获取来源
sourceType = getIntent().getIntExtra(EXTRA_SOURCE, -1);
mapView = findViewById(R.id.map_view);
recyclerSteps = findViewById(R.id.recycler_steps);
mapView.onCreate(savedInstanceState);
if (aMap == null) {
aMap = mapView.getMap();
}
routeSearch = new RouteSearch(this);
routeSearch.setRouteSearchListener(this);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("公交路线规划");
}
// ✅ 初始化定位并开始获取一次位置
initLocation();
parseIntentAndStartSearch();
}
/**
* 初始化定位客户端(只请求一次)
*/
private void initLocation() {
try {
locationClient = new AMapLocationClient(this);
AMapLocationClientOption option = new AMapLocationClientOption();
option.setOnceLocation(true); // 一次性定位
option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
option.setMockEnable(false);
locationClient.setLocationOption(option);
locationClient.setLocationListener(this);
locationClient.startLocation(); // 开始定位
} catch (AMapException e) {
Log.e("RoutePlan", "定位客户端初始化失败", e);
Toast.makeText(this, "定位功能初始化失败,请检查权限", Toast.LENGTH_LONG).show();
// 可以选择 finish() 或降级处理
}
}
/**
* 解析 Intent 并发起公交路线搜索
*/
private void parseIntentAndStartSearch() {
if (isSearching) return;
double targetLat = getIntent().getDoubleExtra("target_lat", 0);
double targetLng = getIntent().getDoubleExtra("target_lng", 0);
if (targetLat == 0 || targetLng == 0) {
Toast.makeText(this, "目标位置无效", Toast.LENGTH_SHORT).show();
finish();
return;
}
// ✅ 动态确定起点
LatLonPoint start = null;
// 情况1:来自 SearchResultActivity -> 使用真实定位
if (sourceType == SOURCE_FROM_HOME_SEARCH && currentLocation != null) {
start = currentLocation;
}
// 情况2:来自 MapFragment -> 使用自定义起点
else if (sourceType == SOURCE_FROM_MAP_DIRECT) {
double startLat = getIntent().getDoubleExtra("start_lat", 0);
double startLng = getIntent().getDoubleExtra("start_lng", 0);
if (startLat != 0 && startLng != 0) {
start = new LatLonPoint(startLat, startLng);
}
}
// 起点为空?提示错误
if (start == null) {
Toast.makeText(this, "无法获取起点位置,请稍后再试", Toast.LENGTH_LONG).show();
finish();
return;
}
LatLonPoint target = new LatLonPoint(targetLat, targetLng);
RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(start, target);
RouteSearch.BusRouteQuery query = new RouteSearch.BusRouteQuery(fromAndTo, RouteSearch.BUS_DEFAULT, "全国", 0);
query.setCityd("全国");
isSearching = true;
routeSearch.calculateBusRouteAsyn(query);
}
// ✅ 定位回调
@Override
public void onLocationChanged(AMapLocation loc) {
if (loc != null && loc.getErrorCode() == 0) {
currentLocation = new LatLonPoint(loc.getLatitude(), loc.getLongitude());
Log.d("RoutePlan", "✅ 获取到真实位置: " + loc.getLatitude() + "," + loc.getLongitude());
} else {
Log.e("RoutePlan", "❌ 定位失败: " + (loc != null ? loc.getErrorInfo() : "null"));
}
}
@Override
public void onBusRouteSearched(BusRouteResult result, int rCode) {
isSearching = false;
if (rCode != 1000 || result == null || result.getPaths().isEmpty()) {
Toast.makeText(this, "未找到公交路线", Toast.LENGTH_SHORT).show();
finish();
return;
}
BusPath bestPath = result.getPaths().get(0);
drawRouteOnMap(bestPath);
StepAdapter adapter = new StepAdapter(bestPath.getSteps());
recyclerSteps.setLayoutManager(new LinearLayoutManager(this));
recyclerSteps.setAdapter(adapter);
String info = String.format("耗时:%d分钟 | 票价:¥%.2f",
bestPath.getDuration() / 60, bestPath.getCost());
Toast.makeText(this, info, Toast.LENGTH_LONG).show();
}
private void drawRouteOnMap(BusPath path) {
aMap.clear();
List<LatLng> allPoints = new ArrayList<>();
for (BusStep step : path.getSteps()) {
boolean added = false;
if (step.getBusLine() != null) {
try {
Method method = step.getBusLine().getClass().getMethod("getPolyline");
Object result = method.invoke(step.getBusLine());
if (result instanceof List) {
for (Object obj : (List<?>) result) {
if (obj instanceof LatLonPoint) {
LatLonPoint p = (LatLonPoint) obj;
allPoints.add(new LatLng(p.getLatitude(), p.getLongitude()));
added = true;
}
}
}
} catch (Exception e) {
Log.d("RoutePlan", "BusLine.getPolyline() 失败: " + e.getMessage());
}
}
if (!added && step.getWalk() != null) {
try {
Method method = step.getWalk().getClass().getMethod("getPolyline");
Object result = method.invoke(step.getWalk());
if (result instanceof List) {
for (Object obj : (List<?>) result) {
if (obj instanceof LatLonPoint) {
LatLonPoint p = (LatLonPoint) obj;
allPoints.add(new LatLng(p.getLatitude(), p.getLongitude()));
added = true;
}
}
}
} catch (Exception e) {
Log.d("RoutePlan", "WalkPath.getPolyline() 失败: " + e.getMessage());
}
}
if (!added) {
// 使用反射处理 Entrance/Exit
Object entrance = step.getEntrance();
Object exit = step.getExit();
try {
if (entrance != null) {
Method method = entrance.getClass().getMethod("getLatLonPoint");
LatLonPoint point = (LatLonPoint) method.invoke(entrance);
if (point != null) {
allPoints.add(new LatLng(point.getLatitude(), point.getLongitude()));
added = true;
}
}
if (exit != null) {
Method method = exit.getClass().getMethod("getLatLonPoint");
LatLonPoint point = (LatLonPoint) method.invoke(exit);
if (point != null) {
allPoints.add(new LatLng(point.getLatitude(), point.getLongitude()));
}
}
} catch (Exception e) {
Log.d("RoutePlan", "通过 Entrance/Exit 获取坐标失败", e);
}
}
}
if (!allPoints.isEmpty()) {
PolylineOptions options = new PolylineOptions()
.addAll(allPoints)
.color(0xFF4A90E2)
.width(12f);
aMap.addPolyline(options);
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (LatLng point : allPoints) {
builder.include(point);
}
LatLngBounds bounds = builder.build();
aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100));
} else {
Toast.makeText(this, "无法绘制路线", Toast.LENGTH_SHORT).show();
}
}
// ✅ 返回键行为控制
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
public void onBackPressed() {
if (sourceType == SOURCE_FROM_MAP_DIRECT) {
// 回到 MainActivity 并打开地图 Tab
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("open_tab", "map");
startActivity(intent);
finish();
} else {
// 默认返回上一页
super.onBackPressed();
}
}
// 其他回调(空实现)
@Override public void onDriveRouteSearched(DriveRouteResult r, int c) {}
@Override public void onWalkRouteSearched(WalkRouteResult r, int c) {}
@Override public void onRideRouteSearched(RideRouteResult r, int c) {}
// 生命周期方法
@Override protected void onResume() { super.onResume(); mapView.onResume(); }
@Override protected void onPause() { super.onPause(); mapView.onPause(); }
@Override protected void onDestroy() {
if (mapView != null) mapView.onDestroy();
if (routeSearch != null) routeSearch.setRouteSearchListener(null);
if (locationClient != null) locationClient.onDestroy();
super.onDestroy();
}
@Override protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
错误:Unhandled exception: com.amap.api.services.core.AMapException、Unhandled exception: java.lang.Exception、`onBackPressed` is no longer called for back gestures; migrate to AndroidX's backward compatible `OnBackPressedDispatcher`
最新发布