diff --git a/bytheway/build.properties b/bytheway/build.properties
index 6fda82f..dfe5a42 100644
--- a/bytheway/build.properties
+++ b/bytheway/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Thu Jul 02 06:09:41 GMT 2026
+#Thu Jul 02 07:36:18 GMT 2026
stageCount=0
libraryProject=
baseVersion=15.20
publishVersion=15.20.0
-buildCount=19
+buildCount=22
baseBetaVersion=15.20.1
diff --git a/bytheway/src/main/AndroidManifest.xml b/bytheway/src/main/AndroidManifest.xml
index 6cca56f..e6d433d 100644
--- a/bytheway/src/main/AndroidManifest.xml
+++ b/bytheway/src/main/AndroidManifest.xml
@@ -3,6 +3,15 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.bytheway">
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/bytheway/src/main/java/cc/winboll/studio/bytheway/activities/GpsListActivity.java b/bytheway/src/main/java/cc/winboll/studio/bytheway/activities/GpsListActivity.java
new file mode 100644
index 0000000..d8b10a6
--- /dev/null
+++ b/bytheway/src/main/java/cc/winboll/studio/bytheway/activities/GpsListActivity.java
@@ -0,0 +1,78 @@
+package cc.winboll.studio.bytheway.activities;
+
+import android.os.Bundle;
+import android.os.Handler;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+import cc.winboll.studio.bytheway.R;
+import cc.winboll.studio.bytheway.adapters.GpsAdapter;
+import cc.winboll.studio.bytheway.helpers.GpsDbManager;
+import cc.winboll.studio.bytheway.models.GpsBean;
+import cc.winboll.studio.libappbase.LogUtils;
+import java.util.List;
+
+/**
+ * GPS定位数据列表展示页面
+ * 支持下拉刷新SQLite本地数据库定位轨迹信息
+ * @author 豆包&ZhanGSKen
+ * 创建时间:2026-07-02 14:49:00
+ * 最后编辑时间:2026-07-02 16:32:13
+ */
+public class GpsListActivity extends AppCompatActivity {
+
+ private SwipeRefreshLayout swipeRefresh;
+ private RecyclerView rvGps;
+ private GpsDbManager dbManager;
+ private GpsAdapter adapter;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_gps_list);
+ LogUtils.i("GpsListActivity", "页面初始化");
+
+ initView();
+ initData();
+ setSwipeRefreshListener();
+ }
+
+ private void initView() {
+ swipeRefresh = findViewById(R.id.swipe_refresh_layout);
+ rvGps = findViewById(R.id.rv_gps_list);
+ dbManager = new GpsDbManager(this);
+ rvGps.setLayoutManager(new LinearLayoutManager(this));
+ LogUtils.i("GpsListActivity", "控件初始化完成");
+ }
+
+ private void initData() {
+ LogUtils.i("GpsListActivity", "开始加载GPS数据库数据");
+ refreshGpsData();
+ }
+
+ private void setSwipeRefreshListener() {
+ swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+ @Override
+ public void onRefresh() {
+ refreshGpsData();
+ }
+ });
+ }
+
+ private void refreshGpsData() {
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ final List gpsDataList = dbManager.queryAllGps();
+ LogUtils.i("GpsListActivity", "查询GPS数据条数:" + gpsDataList.size());
+
+ adapter = new GpsAdapter(GpsListActivity.this, gpsDataList);
+ rvGps.setAdapter(adapter);
+ swipeRefresh.setRefreshing(false);
+ }
+ }, 500);
+ }
+
+}
+
diff --git a/bytheway/src/main/java/cc/winboll/studio/bytheway/activities/SettingsActivity.java b/bytheway/src/main/java/cc/winboll/studio/bytheway/activities/SettingsActivity.java
new file mode 100644
index 0000000..c37b506
--- /dev/null
+++ b/bytheway/src/main/java/cc/winboll/studio/bytheway/activities/SettingsActivity.java
@@ -0,0 +1,23 @@
+package cc.winboll.studio.bytheway.activities;
+
+import android.app.Activity;
+import android.os.Bundle;
+import cc.winboll.studio.bytheway.R;
+
+/**
+ * @Author 豆包&BigPickle&ZhanGSKen
+ * @Date 2026/07/02 15:38
+ * @Describe 应用设置窗口
+ */
+public class SettingsActivity extends Activity {
+
+ public static final String TAG = "SettingsActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_settings);
+
+ }
+
+}
\ No newline at end of file
diff --git a/bytheway/src/main/java/cc/winboll/studio/bytheway/adapters/GpsAdapter.java b/bytheway/src/main/java/cc/winboll/studio/bytheway/adapters/GpsAdapter.java
new file mode 100644
index 0000000..e733d15
--- /dev/null
+++ b/bytheway/src/main/java/cc/winboll/studio/bytheway/adapters/GpsAdapter.java
@@ -0,0 +1,69 @@
+package cc.winboll.studio.bytheway.adapters;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import cc.winboll.studio.bytheway.R;
+import cc.winboll.studio.bytheway.models.GpsBean;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Author 豆包&BigPickle&ZhanGSKen
+ * @Date 2026/07/02 15:10
+ */
+public class GpsAdapter extends RecyclerView.Adapter {
+
+ private final Context context;
+ private final List gpsList;
+ private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ public GpsAdapter(Context context, List gpsList) {
+ this.context = context;
+ this.gpsList = gpsList;
+ }
+
+ @NonNull
+ @Override
+ public GpsHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(context).inflate(R.layout.item_gps, parent, false);
+ return new GpsHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull GpsHolder holder, int position) {
+ GpsBean bean = gpsList.get(position);
+
+ //时间格式化
+ String time = sdf.format(new Date(bean.getReceiveTime()));
+ holder.tvTime.setText("接收时间:" + time);
+
+ //经纬度
+ holder.tvLatLng.setText("纬度:" + bean.getLatitude() + " 经度:" + bean.getLongitude());
+
+ //海拔、精度、速度
+ holder.tvOther.setText("精度:"+bean.getAccuracy()+"m 海拔:"+bean.getAltitude()+"m 速度:"+bean.getSpeed()+"m/s");
+ }
+
+ @Override
+ public int getItemCount() {
+ return gpsList.size();
+ }
+
+ public static class GpsHolder extends RecyclerView.ViewHolder {
+ TextView tvTime, tvLatLng, tvOther;
+
+ public GpsHolder(@NonNull View itemView) {
+ super(itemView);
+ tvTime = itemView.findViewById(R.id.tv_time);
+ tvLatLng = itemView.findViewById(R.id.tv_lat_lng);
+ tvOther = itemView.findViewById(R.id.tv_other);
+ }
+ }
+}
+
diff --git a/bytheway/src/main/java/cc/winboll/studio/bytheway/helpers/GpsDbHelper.java b/bytheway/src/main/java/cc/winboll/studio/bytheway/helpers/GpsDbHelper.java
new file mode 100644
index 0000000..b379a28
--- /dev/null
+++ b/bytheway/src/main/java/cc/winboll/studio/bytheway/helpers/GpsDbHelper.java
@@ -0,0 +1,44 @@
+package cc.winboll.studio.bytheway.helpers;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * GPS数据库创建、版本升级管理
+ * @author 豆包&ZhanGSKen
+ * 创建时间:2026-07-02 15:00:00
+ * 最后编辑时间:2026-07-02 16:35:41
+ */
+public class GpsDbHelper extends SQLiteOpenHelper {
+
+ private static final String DB_NAME = "GpsLocation.db";
+ private static final int DB_VERSION = 1;
+ public static final String TABLE_GPS = "gps_table";
+
+ private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_GPS + " ("
+ + "_id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ + "latitude REAL,"
+ + "longitude REAL,"
+ + "accuracy REAL,"
+ + "altitude REAL,"
+ + "speed REAL,"
+ + "receive_time INTEGER"
+ + ")";
+
+ public GpsDbHelper(final Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(final SQLiteDatabase db) {
+ db.execSQL(CREATE_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_GPS);
+ onCreate(db);
+ }
+}
+
diff --git a/bytheway/src/main/java/cc/winboll/studio/bytheway/helpers/GpsDbManager.java b/bytheway/src/main/java/cc/winboll/studio/bytheway/helpers/GpsDbManager.java
new file mode 100644
index 0000000..6827d06
--- /dev/null
+++ b/bytheway/src/main/java/cc/winboll/studio/bytheway/helpers/GpsDbManager.java
@@ -0,0 +1,112 @@
+package cc.winboll.studio.bytheway.helpers;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import cc.winboll.studio.bytheway.models.GpsBean;
+import cc.winboll.studio.libappbase.LogUtils;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * GPS SQLite数据库数据管理工具
+ * 负责本地定位轨迹插入、查询、时间段筛选、清空操作
+ * @author 豆包&ZhanGSKen
+ * 创建时间:2026-07-02 15:03:00
+ * 最后编辑时间:2026-07-02 16:35:41
+ */
+public class GpsDbManager {
+
+ private static final String TABLE_GPS = "gps_table";
+ private final GpsDbHelper dbHelper;
+
+ public GpsDbManager(final Context context) {
+ dbHelper = new GpsDbHelper(context);
+ }
+
+ //插入单条GPS定位数据
+ public void insertGps(final GpsBean bean) {
+ final SQLiteDatabase db = dbHelper.getWritableDatabase();
+ final ContentValues values = new ContentValues();
+
+ values.put("latitude", bean.getLatitude());
+ values.put("longitude", bean.getLongitude());
+ values.put("accuracy", bean.getAccuracy());
+ values.put("altitude", bean.getAltitude());
+ values.put("speed", bean.getSpeed());
+ values.put("receive_time", bean.getReceiveTime());
+
+ db.insert(TABLE_GPS, null, values);
+ LogUtils.i("GpsDbManager", "GPS数据插入成功");
+ db.close();
+ }
+
+ //查询全部GPS记录,按时间倒序排列
+ public List queryAllGps() {
+ final List list = new ArrayList();
+ final SQLiteDatabase db = dbHelper.getReadableDatabase();
+
+ final Cursor cursor = db.query(TABLE_GPS, null, null, null, null, null, "receive_time DESC");
+
+ if (cursor.moveToFirst()) {
+ do {
+ final GpsBean bean = new GpsBean();
+ bean.setId(cursor.getInt(0));
+ bean.setLatitude(cursor.getDouble(1));
+ bean.setLongitude(cursor.getDouble(2));
+ bean.setAccuracy(cursor.getFloat(3));
+ bean.setAltitude(cursor.getDouble(4));
+ bean.setSpeed(cursor.getFloat(5));
+ bean.setReceiveTime(cursor.getLong(6));
+
+ list.add(bean);
+ } while (cursor.moveToNext());
+ }
+
+ LogUtils.i("GpsDbManager", "查询全部GPS条数:" + list.size());
+ cursor.close();
+ db.close();
+ return list;
+ }
+
+ //根据时间区间查询GPS轨迹
+ public List queryByTime(final long startTime, final long endTime) {
+ final List list = new ArrayList();
+ final SQLiteDatabase db = dbHelper.getReadableDatabase();
+
+ final String where = "receive_time >= ? AND receive_time <= ?";
+ final String[] args = {String.valueOf(startTime), String.valueOf(endTime)};
+
+ final Cursor cursor = db.query(TABLE_GPS, null, where, args, null, null, "receive_time ASC");
+
+ if (cursor.moveToFirst()) {
+ do {
+ final GpsBean bean = new GpsBean();
+ bean.setId(cursor.getInt(0));
+ bean.setLatitude(cursor.getDouble(1));
+ bean.setLongitude(cursor.getDouble(2));
+ bean.setAccuracy(cursor.getFloat(3));
+ bean.setAltitude(cursor.getDouble(4));
+ bean.setSpeed(cursor.getFloat(5));
+ bean.setReceiveTime(cursor.getLong(6));
+
+ list.add(bean);
+ } while (cursor.moveToNext());
+ }
+
+ LogUtils.i("GpsDbManager", "时间段查询GPS条数:" + list.size());
+ cursor.close();
+ db.close();
+ return list;
+ }
+
+ //清空所有本地GPS历史数据
+ public void clearAllGps() {
+ final SQLiteDatabase db = dbHelper.getWritableDatabase();
+ db.delete(TABLE_GPS, null, null);
+ LogUtils.i("GpsDbManager", "已清空全部GPS数据库数据");
+ db.close();
+ }
+}
+
diff --git a/bytheway/src/main/java/cc/winboll/studio/bytheway/models/GpsBean.java b/bytheway/src/main/java/cc/winboll/studio/bytheway/models/GpsBean.java
new file mode 100644
index 0000000..0960ee1
--- /dev/null
+++ b/bytheway/src/main/java/cc/winboll/studio/bytheway/models/GpsBean.java
@@ -0,0 +1,44 @@
+package cc.winboll.studio.bytheway.models;
+
+import java.util.Date;
+/**
+ * @Author 豆包&BigPickle&ZhanGSKen
+ * @Date 2026/07/02 14:56
+ */
+public class GpsBean {
+ private int id;
+ private double latitude; //纬度
+ private double longitude; //经度
+ private float accuracy; //精度
+ private double altitude; //海拔
+ private float speed; //速度
+ private long receiveTime; //接收时间戳
+
+ public GpsBean() {}
+
+ public GpsBean(double latitude, double longitude, float accuracy, double altitude, float speed, long receiveTime) {
+ this.latitude = latitude;
+ this.longitude = longitude;
+ this.accuracy = accuracy;
+ this.altitude = altitude;
+ this.speed = speed;
+ this.receiveTime = receiveTime;
+ }
+
+ //get set 方法
+ public int getId() { return id; }
+ public void setId(int id) { this.id = id; }
+ public double getLatitude() { return latitude; }
+ public void setLatitude(double latitude) { this.latitude = latitude; }
+ public double getLongitude() { return longitude; }
+ public void setLongitude(double longitude) { this.longitude = longitude; }
+ public float getAccuracy() { return accuracy; }
+ public void setAccuracy(float accuracy) { this.accuracy = accuracy; }
+ public double getAltitude() { return altitude; }
+ public void setAltitude(double altitude) { this.altitude = altitude; }
+ public float getSpeed() { return speed; }
+ public void setSpeed(float speed) { this.speed = speed; }
+ public long getReceiveTime() { return receiveTime; }
+ public void setReceiveTime(long receiveTime) { this.receiveTime = receiveTime; }
+}
+
diff --git a/bytheway/src/main/java/cc/winboll/studio/bytheway/services/GpsReceiveService.java b/bytheway/src/main/java/cc/winboll/studio/bytheway/services/GpsReceiveService.java
new file mode 100644
index 0000000..5c1946f
--- /dev/null
+++ b/bytheway/src/main/java/cc/winboll/studio/bytheway/services/GpsReceiveService.java
@@ -0,0 +1,123 @@
+package cc.winboll.studio.bytheway.services;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.IBinder;
+import cc.winboll.studio.bytheway.helpers.GpsDbManager;
+import cc.winboll.studio.bytheway.models.GpsBean;
+import cc.winboll.studio.libappbase.LogUtils;
+
+/**
+ * @Author 豆包&BigPickle&ZhanGSKen
+ * @Date 2026/07/02 15:33
+ * @Describe 动态注册定位广播,接收GPS数据并持久化存入SQLite数据库。单例独占模式,自带重复启动拦截,对外静态统一启停接口
+ */
+public class GpsReceiveService extends Service {
+
+ public static final String TAG = "GpsReceiveService";
+
+ private static boolean serviceRunning = false;
+ private GpsDbManager dbManager;
+ private BroadcastReceiver gpsBroadcastReceiver;
+
+ /**
+ * 外部统一静态启动服务
+ */
+ public static void startGpsService(final Context context) {
+ if (serviceRunning) {
+ LogUtils.i("GpsReceiveService", "服务已运行,无需重复启动");
+ return;
+ }
+ final Intent intent = new Intent(context, GpsReceiveService.class);
+ context.startService(intent);
+ LogUtils.i("GpsReceiveService", "GPS接收服务启动请求发送");
+ }
+
+ /**
+ * 外部统一静态关闭服务
+ */
+ public static void stopGpsService(final Context context) {
+ if (!serviceRunning) {
+ LogUtils.i("GpsReceiveService", "服务未运行,无需关闭");
+ return;
+ }
+ final Intent intent = new Intent(context, GpsReceiveService.class);
+ context.stopService(intent);
+ LogUtils.i("GpsReceiveService", "GPS接收服务停止请求发送");
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ serviceRunning = true;
+ dbManager = new GpsDbManager(getApplicationContext());
+ registerGpsBroadcast();
+ LogUtils.i("GpsReceiveService", "GPS接收服务创建完成");
+ }
+
+ /**
+ * 动态注册GPS定位广播接收器
+ */
+ private void registerGpsBroadcast() {
+ gpsBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ parseAndSaveGpsData(intent);
+ }
+ };
+ final IntentFilter filter = new IntentFilter();
+ //GPS定位广播动作,与你定位发送广播对应
+ filter.addAction("android.location.GPS_LOCATION_BROADCAST");
+ registerReceiver(gpsBroadcastReceiver, filter);
+ LogUtils.i("GpsReceiveService", "GPS广播动态注册成功");
+ }
+
+ /**
+ * 解析广播GPS数据并写入SQLite数据库
+ */
+ private void parseAndSaveGpsData(final Intent intent) {
+ final double latitude = intent.getDoubleExtra("latitude", 0);
+ final double longitude = intent.getDoubleExtra("longitude", 0);
+ final float accuracy = intent.getFloatExtra("accuracy", 0);
+ final double altitude = intent.getDoubleExtra("altitude", 0);
+ final float speed = intent.getFloatExtra("speed", 0);
+ final long time = intent.getLongExtra("receive_time", System.currentTimeMillis());
+
+ final GpsBean bean = new GpsBean();
+ bean.setLatitude(latitude);
+ bean.setLongitude(longitude);
+ bean.setAccuracy(accuracy);
+ bean.setAltitude(altitude);
+ bean.setSpeed(speed);
+ bean.setReceiveTime(time);
+
+ dbManager.insertGps(bean);
+ LogUtils.d("GpsReceiveService", "收到GPS广播,已保存定位数据");
+ }
+
+ @Override
+ public int onStartCommand(final Intent intent, final int flags, final int startId) {
+ //单例不重启模式,被杀不自动重启
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(final Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ serviceRunning = false;
+ //反注册广播,防止内存泄漏
+ if (gpsBroadcastReceiver != null) {
+ unregisterReceiver(gpsBroadcastReceiver);
+ }
+ LogUtils.i("GpsReceiveService", "GPS接收服务已销毁,广播已解绑");
+ }
+
+}
diff --git a/bytheway/src/main/res/layout/activity_gps_list.xml b/bytheway/src/main/res/layout/activity_gps_list.xml
new file mode 100644
index 0000000..fa608fa
--- /dev/null
+++ b/bytheway/src/main/res/layout/activity_gps_list.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/bytheway/src/main/res/layout/activity_settings.xml b/bytheway/src/main/res/layout/activity_settings.xml
new file mode 100644
index 0000000..6684a21
--- /dev/null
+++ b/bytheway/src/main/res/layout/activity_settings.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/bytheway/src/main/res/layout/item_gps.xml b/bytheway/src/main/res/layout/item_gps.xml
new file mode 100644
index 0000000..b60c6b3
--- /dev/null
+++ b/bytheway/src/main/res/layout/item_gps.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+