Android Java应用获取区域海拔:判定无人机挂载设备飞行状态
解决Android应用获取地面海拔以判定无人机飞行状态的问题
核心逻辑
你当前通过GPS获取的是手机的绝对海拔,要判定飞行状态,需要获取当前经纬度对应的地面地形海拔,计算两者的差值,当差值超过设定阈值时即可判定为飞行状态。
可行解决方案
方法1:调用在线地理高程API
这是最便捷的实现方案,通过当前获取到的经纬度,请求专业地理数据服务的高程接口,获取对应位置的地面海拔:
- 确保应用在
AndroidManifest.xml中申请INTERNET权限 - 在获取到经纬度后,发起异步HTTP请求到高程API
- 解析返回结果得到地面海拔,计算与手机海拔的差值
方法2:集成离线高程数据集
如果应用需要在无网络环境下运行,可以集成开源离线高程数据集(如SRTM),将数据打包进应用或通过本地存储加载,根据经纬度查询对应海拔。但该方案会增加应用体积,适合特定离线场景。
代码修改示例
以下是在你现有代码基础上,添加在线高程API调用逻辑的完整修改版本:
首先添加网络权限到AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
修改后的TimeService类:
public class TimeService extends Service{ private final static String TAG = TimeService.class.getName(); private LocationEntity location = new LocationEntity(); private Handler handler; private FusedLocationProviderClient fusedLocationProviderClient; private LocationRequest newlocationRequest; private AppDatabase appDatabase; // 飞行判定阈值(可根据需求调整,单位:米) private static final double FLIGHT_THRESHOLD = 20.0; @Override public void onCreate() { super.onCreate(); fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); appDatabase = AppDatabase.getDbIntance(this); locationCallback = new LocationCallback() { @Override public void onLocationResult(@NonNull LocationResult locationResult) { super.onLocationResult(locationResult); Location location = locationResult.getLastLocation(); if (location == null) return; Log.d("TAG", "onLocationResult: 经度="+location.getLongitude()+" 纬度="+location.getLatitude()+" 海拔="+location.getAltitude()); // 获取地面海拔并判定飞行状态 fetchGroundElevation(location.getLatitude(), location.getLongitude(), location.getAltitude()); } }; // 初始化Location配置 locationSettings(); startLocationUpdate(); handler = new Handler(); Runnable runnable = () -> { startLocationUpdate(); Log.d("TAG", "run: 每30秒更新一次位置"); handler.postDelayed(this, 30000L); }; handler.post(runnable); } // 配置LocationRequest参数 public void locationSettings() { newlocationRequest = new LocationRequest(); newlocationRequest.setInterval(30000); newlocationRequest.setFastestInterval(5000); newlocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } public void updateGPS() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } fusedLocationProviderClient.getLastLocation().addOnSuccessListener(position -> { if (position == null) return; Log.d("TAG", "updateGPS: 经度="+position.getLongitude()+" 纬度="+position.getLatitude()+" 海拔="+position.getAltitude()); location.setLongitude(position.getLongitude()); location.setLatitude(position.getLatitude()); location.setAltitude(position.getAltitude()); location.setAccuracy(position.getAccuracy()); location.setSpeed(position.getSpeed()); appDatabase.locationDao().insert(location); // 同步判定飞行状态 fetchGroundElevation(position.getLatitude(), position.getLongitude(), position.getAltitude()); }); } public void startLocationUpdate() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } fusedLocationProviderClient.requestLocationUpdates(newlocationRequest, locationCallback, null); updateGPS(); } // 获取地面海拔并判定飞行状态 private void fetchGroundElevation(double latitude, double longitude, double phoneAltitude) { // 替换为你选用的高程API地址,格式需匹配API要求 String apiUrl = String.format("你的高程API请求地址?lat=%f&lon=%f", latitude, longitude); // 使用OkHttp发起异步请求(需添加OkHttp依赖) OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(apiUrl).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { Log.e(TAG, "获取地面海拔失败: "+e.getMessage()); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (!response.isSuccessful()) { Log.e(TAG, "API响应失败: "+response.code()); return; } String responseData = response.body().string(); double groundElevation = parseGroundElevationFromResponse(responseData); // 计算相对高度,判定飞行状态 double relativeHeight = phoneAltitude - groundElevation; boolean isFlying = relativeHeight >= FLIGHT_THRESHOLD; Log.d(TAG, "地面海拔: "+groundElevation+" 相对高度: "+relativeHeight+" 是否飞行: "+isFlying); // 可将飞行状态存入数据库或发送通知 } }); } // 解析API响应获取地面海拔(需根据实际API返回格式调整) private double parseGroundElevationFromResponse(String response) { // 示例:假设API返回JSON格式 {"elevation": 123.45} try { JSONObject jsonObject = new JSONObject(response); return jsonObject.getDouble("elevation"); } catch (JSONException e) { Log.e(TAG, "解析海拔数据失败: "+e.getMessage()); return 0.0; } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
注意事项
- 选择高程API时,需关注其精度、请求限制及费用(部分免费API有调用次数上限)
- 网络请求必须放在异步线程中,避免阻塞主线程
- 可对地面海拔数据进行本地缓存,减少重复请求
- 若使用离线数据集,需注意数据更新周期和存储优化
内容的提问来源于stack exchange,提问作者Patrick Renaud
相关产品推荐
相关产品推荐

