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 @@ + + + + + + + + + + +