diff --git a/positions/build.gradle b/positions/build.gradle index b8401af..b7aaa28 100644 --- a/positions/build.gradle +++ b/positions/build.gradle @@ -45,6 +45,9 @@ android { dependencies { api fileTree(dir: 'libs', include: ['*.jar']) + + // 谷歌定位服务核心依赖(FusedLocationProviderClient所在库) + api 'com.google.android.gms:play-services-location:21.0.1' // SSH api 'com.jcraft:jsch:0.1.55' diff --git a/positions/build.properties b/positions/build.properties index 4968ed8..f8c4e4d 100644 --- a/positions/build.properties +++ b/positions/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Mon Sep 29 18:02:11 HKT 2025 +#Mon Sep 29 10:40:51 GMT 2025 stageCount=2 libraryProject= baseVersion=15.0 publishVersion=15.0.1 -buildCount=0 +buildCount=2 baseBetaVersion=15.0.2 diff --git a/positions/src/main/AndroidManifest.xml b/positions/src/main/AndroidManifest.xml index 277d9bb..65f5e10 100644 --- a/positions/src/main/AndroidManifest.xml +++ b/positions/src/main/AndroidManifest.xml @@ -2,7 +2,20 @@ + + + + + + + + + + + + + + + diff --git a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java index f824af5..635b835 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java +++ b/positions/src/main/java/cc/winboll/studio/positions/MainActivity.java @@ -5,6 +5,9 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import cc.winboll.studio.libappbase.LogView; import com.hjq.toast.ToastUtils; +import android.view.View; +import cc.winboll.studio.positions.activities.LocationActivity; +import android.content.Intent; public class MainActivity extends AppCompatActivity { @@ -28,4 +31,8 @@ public class MainActivity extends AppCompatActivity { super.onResume(); mLogView.start(); } + + public void onPositions(View view) { + startActivity(new Intent(this, LocationActivity.class)); + } } diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java new file mode 100644 index 0000000..ba8830c --- /dev/null +++ b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java @@ -0,0 +1,219 @@ +package cc.winboll.studio.positions.activities; + + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/09/29 18:22 + * @Describe 当前位置实时显示 + */ + + +import android.Manifest; +import android.content.pm.PackageManager; +import android.location.Location; +import android.os.Bundle; +import android.widget.TextView; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationResult; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.tasks.OnSuccessListener; +import cc.winboll.studio.positions.R; + + +/** + * 实时定位活动窗口: + * 1. 申请定位必需权限(精确定位+粗略定位) + * 2. 初始化FusedLocationProviderClient(谷歌官方定位服务,兼容所有安卓版本) + * 3. 实时监听位置变化,更新显示经度、纬度 + */ +public class LocationActivity extends AppCompatActivity { + + public static final String TAG = "LocationActivity"; + + // 1. 核心组件与常量定义 + private static final int REQUEST_LOCATION_PERMISSIONS = 1004; // 定位权限请求码 + private FusedLocationProviderClient fusedLocationClient; // 定位核心客户端 + private LocationCallback locationCallback; // 位置变化监听器 + private LocationRequest locationRequest; // 定位请求配置(频率、精度等) + + // UI控件:用于显示经纬度(需在布局中定义对应ID) + private TextView tvLongitude; // 经度显示 + private TextView tvLatitude; // 纬度显示 + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // 2. 加载布局(需手动创建对应布局文件,见下方说明) + setContentView(R.layout.activity_location); + + // 3. 绑定UI控件(与布局文件中的TextView ID对应) + tvLongitude = findViewById(R.id.tv_longitude); + tvLatitude = findViewById(R.id.tv_latitude); + + // 4. 初始化定位相关组件 + initLocationConfig(); + + // 5. 检查并申请定位权限(无权限则申请,有权限则直接启动定位) + if (checkLocationPermissions()) { + startRealTimeLocation(); // 权限已授予 → 启动实时定位 + } else { + requestLocationPermissions(); // 权限未授予 → 申请权限 + } + } + + + /** + * 初始化定位配置:设置定位精度、更新频率等 + */ + private void initLocationConfig() { + // 初始化定位客户端(谷歌官方推荐,替代旧的LocationManager) + fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); + + // 配置定位请求:实时更新(1秒请求一次,最小间隔500毫秒,最高精度) + locationRequest = new LocationRequest.Builder(1000) // 定位更新间隔(毫秒) + .setMinUpdateIntervalMillis(500) // 最小更新间隔(避免频繁更新耗电) + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) // 高精度定位(优先GPS) + .build(); + + // 初始化位置变化监听器:位置更新时触发(实时更新UI) + locationCallback = new LocationCallback() { + @Override + public void onLocationResult(@NonNull LocationResult locationResult) { + super.onLocationResult(locationResult); + // 获取最新位置信息(locationResult包含最近一次或多次位置) + Location latestLocation = locationResult.getLastLocation(); + if (latestLocation != null) { + // 6. 提取经纬度并更新UI(实时显示) + double longitude = latestLocation.getLongitude(); // 经度(东经为正,西经为负) + double latitude = latestLocation.getLatitude(); // 纬度(北纬为正,南纬为负) + + // 更新TextView显示(保留6位小数,精度足够日常使用) + tvLongitude.setText(String.format("当前经度:%.6f", longitude)); + tvLatitude.setText(String.format("当前纬度:%.6f", latitude)); + } + } + }; + } + + + /** + * 检查定位必需权限是否已授予(精确定位+粗略定位,覆盖所有安卓版本) + */ + private boolean checkLocationPermissions() { + // 安卓12+(API31+)新增精确定位权限,需同时检查2个权限;低版本只需检查1个 + /*if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED + && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; + } else {*/ + return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; + //} + } + + + /** + * 申请定位必需权限(弹系统授权弹窗) + */ + private void requestLocationPermissions() { + /*if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + // 安卓12+:同时申请精确定位+粗略定位 + ActivityCompat.requestPermissions( + this, + new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, + REQUEST_LOCATION_PERMISSIONS + ); + } else {*/ + // 安卓12以下:仅申请精确定位(包含粗略定位能力) + ActivityCompat.requestPermissions( + this, + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + REQUEST_LOCATION_PERMISSIONS + ); + //} + } + + + /** + * 启动实时定位:注册位置监听器,开始接收位置更新 + */ + private void startRealTimeLocation() { + // 权限兜底检查(避免异常) + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + Toast.makeText(this, "定位权限未授予,无法启动定位", Toast.LENGTH_SHORT).show(); + return; + } + + // 1. 先获取一次当前位置(快速显示初始经纬度) + fusedLocationClient.getLastLocation() + .addOnSuccessListener(this, new OnSuccessListener() { + @Override + public void onSuccess(Location location) { + if (location != null) { + // 显示初始经纬度 + tvLongitude.setText(String.format("当前经度:%.6f", location.getLongitude())); + tvLatitude.setText(String.format("当前纬度:%.6f", location.getLatitude())); + } else { + // 无历史位置(如首次启动),提示“等待定位更新” + tvLongitude.setText("当前经度:等待更新..."); + tvLatitude.setText("当前纬度:等待更新..."); + } + } + }); + + // 2. 注册监听器,接收实时位置更新(持续监听) + fusedLocationClient.requestLocationUpdates( + locationRequest, + locationCallback, + getMainLooper() // 在主线程更新UI(避免线程异常) + ); + } + + + /** + * 处理权限申请结果(用户同意/拒绝后触发) + */ + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_LOCATION_PERMISSIONS) { + // 检查是否所有必需权限都已授予 + boolean allGranted = true; + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + allGranted = false; + break; + } + } + + if (allGranted) { + // 权限同意 → 启动实时定位 + startRealTimeLocation(); + } else { + // 权限拒绝 → 提示用户(无法定位) + Toast.makeText(this, "定位权限被拒绝,无法显示位置信息", Toast.LENGTH_SHORT).show(); + tvLongitude.setText("当前经度:无权限"); + tvLatitude.setText("当前纬度:无权限"); + } + } + } + + + /** + * 活动销毁时:停止定位监听(避免内存泄漏、减少耗电) + */ + @Override + protected void onDestroy() { + super.onDestroy(); + // 移除定位监听器(核心:防止Activity销毁后仍在监听,导致内存泄漏) + if (fusedLocationClient != null && locationCallback != null) { + fusedLocationClient.removeLocationUpdates(locationCallback); + } + } +} + diff --git a/positions/src/main/res/layout/activity_location.xml b/positions/src/main/res/layout/activity_location.xml new file mode 100644 index 0000000..2d9895d --- /dev/null +++ b/positions/src/main/res/layout/activity_location.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/positions/src/main/res/layout/activity_main.xml b/positions/src/main/res/layout/activity_main.xml index 8000fb4..97e0df2 100644 --- a/positions/src/main/res/layout/activity_main.xml +++ b/positions/src/main/res/layout/activity_main.xml @@ -26,11 +26,11 @@ android:layout_weight="1.0" android:gravity="center_vertical|center_horizontal"> - + android:onClick="onPositions"/>