效果图:
这个操作是,先开启手机app的定位权限,左上角开始记录,目的地到达后,再次点击左上角,结束;点击右上角,是记录的轨迹以及你所走的总距离以及时间等;记录的数据是保存在数据库中的;
导入的各类包如下图1、2所示:
图片资源:
以上两张图片把基本的目录结构也贴出来了,不要缺漏了 !
manifest.xml【添加一些必要的权限】
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.application.locationpath">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission
android:name="android.permission.CHANGE_CONFIGURATION"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:requestLegacyExternalStorage="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.LocationPath"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".RecordActivity"
android:screenOrientation="portrait">
</activity>
<activity
android:name=".RecordShowActivity"
android:screenOrientation="portrait" />
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="你的key" />
<service android:name="com.amap.api.location.APSService" />
</application>
</manifest>
不知道key怎么获取的,看我上篇文章!
build.gradle(:app) 添加依赖
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
各类图片我放在百度网盘里,大家需要的自行去取哈
链接:https://pan.baidu.com/s/1BmKquARhydJAdyviNjDJ_A
提取码:207k
layout布局我在这里也不详细叙述了;我放到百度网盘里,你们有需要的自行去取哦!
链接:https://pan.baidu.com/s/1bTM79fXbEzTQ5wH2ORF0nQ
提取码:s8pk
java代码:
目录
首先要将数据库建好:
DbAdapter.java
package com.application.locationpath;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* 数据库相关操作,用于存取轨迹记录
*/
public class DbAdapter {
public static final String KEY_ID = "id";
public static final String KEY_DISTANCE = "distance";
public static final String KEY_DURATION = "duration";
public static final String KEY_SPEED = "averagespeed";
public static final String KEY_LINE = "pathline";
public static final String KEY_START = "startpoint";
public static final String KEY_END = "endpoint";
public static final String KEY_DATE = "date";
private final static String DATABASE_PATH = android.os.Environment
.getExternalStorageDirectory().getAbsolutePath() + "/recordPath";
static final String DATABASE_NAME = DATABASE_PATH + "/" + "record.db";
private static final int DATABASE_VERSION = 1;
private static final String RECORD_TABLE = "record";
private static final String RECORD_CREATE = "create table if not exists record("
+ KEY_ID
+ " integer primary key autoincrement,"
+ "startpoint STRING,"
+ "endpoint STRING,"
+ "pathline STRING,"
+ "distance STRING,"
+ "duration STRING,"
+ "averagespeed STRING,"
+ "date STRING" + ");";
public static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, context.getFilesDir() + "/" + "record.db", null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(RECORD_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
private Context mCtx;
private DatabaseHelper dbHelper;
private SQLiteDatabase db;
// constructor
public DbAdapter(Context ctx) {
this.mCtx = ctx;
dbHelper = new DatabaseHelper(mCtx);
}
public void open() throws SQLException {
db = dbHelper.getWritableDatabase();
}
public void close() {
dbHelper.close();
}
public Cursor getall() {
return db.rawQuery("SELECT * FROM record", null);
}
// remove an entry
public boolean delete(long rowId) {
return db.delete(RECORD_TABLE, "id=" + rowId, null) > 0;
}
/**
* 数据库存入一条轨迹
*/
public long createrecord(String distance, String duration,
String averagespeed, String pathline, String startpoint,
String endpoint, String date) {
ContentValues args = new ContentValues();
args.put("distance", distance);
args.put("duration", duration);
args.put("averagespeed", averagespeed);
args.put("pathline", pathline);
args.put("startpoint", startpoint);
args.put("endpoint", endpoint);
args.put("date", date);
return db.insert(RECORD_TABLE, null, args);
}
/**
* 查询所有轨迹记录
*/
@SuppressLint("Range")
public List<PathRecord> queryRecordAll() {
List<PathRecord> allRecord = new ArrayList<PathRecord>();
Cursor allRecordCursor = db.query(RECORD_TABLE, getColumns(), null,
null, null, null, null);
while (allRecordCursor.moveToNext()) {
PathRecord record = new PathRecord();
record.setId(allRecordCursor.getInt(allRecordCursor
.getColumnIndex(DbAdapter.KEY_ID)));
record.setDistance(allRecordCursor.getString(allRecordCursor
.getColumnIndex(DbAdapter.KEY_DISTANCE)));
record.setDuration(allRecordCursor.getString(allRecordCursor
.getColumnIndex(DbAdapter.KEY_DURATION)));
record.setDate(allRecordCursor.getString(allRecordCursor
.getColumnIndex(DbAdapter.KEY_DATE)));
String lines = allRecordCursor.getString(allRecordCursor
.getColumnIndex(DbAdapter.KEY_LINE));
record.setPathline(Util.parseLocations(lines));
record.setStartpoint(Util.parseLocation(allRecordCursor
.getString(allRecordCursor
.getColumnIndex(DbAdapter.KEY_START))));
record.setEndpoint(Util.parseLocation(allRecordCursor
.getString(allRecordCursor
.getColumnIndex(DbAdapter.KEY_END))));
allRecord.add(record);
}
Collections.reverse(allRecord);
return allRecord;
}
/**
* 按照id查询
*/
@SuppressLint("Range")
public PathRecord queryRecordById(int mRecordItemId) {
String where = KEY_ID + "=?";
String[] selectionArgs = new String[]{String.valueOf(mRecordItemId)};
Cursor cursor = db.query(RECORD_TABLE, getColumns(), where,
selectionArgs, null, null, null);
PathRecord record = new PathRecord();
if (cursor.moveToNext()) {
record.setId(cursor.getInt(cursor
.getColumnIndex(DbAdapter.KEY_ID)));
record.setDistance(cursor.getString(cursor
.getColumnIndex(DbAdapter.KEY_DISTANCE)));
record.setDuration(cursor.getString(cursor
.getColumnIndex(DbAdapter.KEY_DURATION)));
record.setDate(cursor.getString(cursor
.getColumnIndex(DbAdapter.KEY_DATE)));
String lines = cursor.getString(cursor
.getColumnIndex(DbAdapter.KEY_LINE));
record.setPathline(Util.parseLocations(lines));
record.setStartpoint(Util.parseLocation(cursor.getString(cursor
.getColumnIndex(DbAdapter.KEY_START))));
record.setEndpoint(Util.parseLocation(cursor.getString(cursor
.getColumnIndex(DbAdapter.KEY_END))));
}
return record;
}
private String[] getColumns() {
return new String[]{KEY_ID, KEY_DISTANCE, KEY_DURATION, KEY_SPEED,
KEY_LINE, KEY_START, KEY_END, KEY_DATE};
}
}
Util 工具类不可少:
package com.application.locationpath;
import java.util.ArrayList;
import java.util.List;
import com.amap.api.location.AMapLocation;
import com.amap.api.maps.model.LatLng;
import com.amap.api.trace.TraceLocation;
public class Util {
/**
* 将AMapLocation List 转为TraceLocation list
*/
public static List<TraceLocation> parseTraceLocationList(
List<AMapLocation> list) {
List<TraceLocation> traceList = new ArrayList<>();
if (list == null) {
return traceList;
}
for (int i = 0; i < list.size(); i++) {
TraceLocation location = new TraceLocation();
AMapLocation amapLocation = list.get(i);
location.setBearing(amapLocation.getBearing());
location.setLatitude(amapLocation.getLatitude());
location.setLongitude(amapLocation.getLongitude());
location.setSpeed(amapLocation.getSpeed());
location.setTime(amapLocation.getTime());
traceList.add(location);
}
return traceList;
}
public static TraceLocation parseTraceLocation(AMapLocation amapLocation) {
TraceLocation location = new TraceLocation();
location.setBearing(amapLocation.getBearing());
location.setLatitude(amapLocation.getLatitude());
location.setLongitude(amapLocation.getLongitude());
location.setSpeed(amapLocation.getSpeed());
location.setTime(amapLocation.getTime());
return location;
}
/**
* 将AMapLocation List 转为LatLng list
*/
public static List<LatLng> parseLatLngList(List<AMapLocation> list) {
List<LatLng> traceList = new ArrayList<>();
if (list == null) {
return traceList;
}
for (int i = 0; i < list.size(); i++) {
AMapLocation loc = list.get(i);
double lat = loc.getLatitude();
double lng = loc.getLongitude();
LatLng latlng = new LatLng(lat, lng);
traceList.add(latlng);
}
return traceList;
}
public static AMapLocation parseLocation(String latLonStr) {
if (latLonStr == null || latLonStr.equals("") || latLonStr.equals("[]")) {
return null;
}
String[] loc = latLonStr.split(",");
AMapLocation location = null;
if (loc.length == 6) {
location = new AMapLocation(loc[2]);
location.setProvider(loc[2]);
location.setLatitude(Double.parseDouble(loc[0]));
location.setLongitude(Double.parseDouble(loc[1]));
location.setTime(Long.parseLong(loc[3]));
location.setSpeed(Float.parseFloat(loc[4]));
location.setBearing(Float.parseFloat(loc[5]));
}else if(loc.length == 2){
location = new AMapLocation("gps");
location.setLatitude(Double.parseDouble(loc[0]));
location.setLongitude(Double.parseDouble(loc[1]));
}
return location;
}
public static ArrayList<AMapLocation> parseLocations(String latLonStr) {
ArrayList<AMapLocation> locations = new ArrayList<>();
String[] latLonStrs = latLonStr.split(";");
for (int i = 0; i < latLonStrs.length; i++) {
AMapLocation location = Util.parseLocation(latLonStrs[i]);
if (location != null) {
locations.add(location);
}
}
return locations;
}
}
EmulatorService.java
package com.application.locationpath;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.location.provider.ProviderProperties;
import android.os.Binder;
import android.os.IBinder;
import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
public class EmulatorService extends Service {
public static double latitude;
public static double longitude;
public boolean isMockOpen() {
String strMock = Settings.Secure.ALLOW_MOCK_LOCATION;
strMock = Settings.Secure.getString(getApplicationContext()
.getContentResolver(), strMock);
if (!TextUtils.isEmpty(strMock) && !strMock.equals("0")) {
return true;
}
return false;
}
private Thread thread = new Thread() {
public void run() {
while (true) {
if (latitude == 0 || longitude == 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
continue;
}
if(!isMockOpen()){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
continue;
}
LocationManager locmanag = (LocationManager) EmulatorService.this
.getSystemService(Context.LOCATION_SERVICE);
String mock = LocationManager.GPS_PROVIDER;
locmanag.addTestProvider(mock, false, true, false, false,
false, false, false, ProviderProperties.POWER_USAGE_LOW, ProviderProperties.ACCURACY_FINE);
locmanag.setTestProviderEnabled(mock, true);
Location loc = new Location(mock);
loc.setTime(System.currentTimeMillis());
// 下面这两句很关键
loc.setLatitude(latitude);
loc.setLongitude(longitude);
loc.setAccuracy(Criteria.ACCURACY_FINE);// 精确度
loc.setSpeed(50);
if (android.os.Build.VERSION.SDK_INT >= 17) {
loc.setElapsedRealtimeNanos(SystemClock
.elapsedRealtimeNanos());// 实时运行时间
}
locmanag.setTestProviderStatus(mock,
LocationProvider.AVAILABLE, null,
System.currentTimeMillis());
locmanag.setTestProviderLocation(mock, loc);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
@Override
public IBinder onBind(Intent intent) {
thread.start();
// TODO Auto-generated method stub
return new EmulatorBinder();
}
public class EmulatorBinder extends Binder {
public void setEmulatorLocation(double latitude, double longitude) {
setLocation(latitude, longitude);
}
}
private void setLocation(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
}
PathRecord.java
package com.application.locationpath;
import java.util.ArrayList;
import java.util.List;
import com.amap.api.location.AMapLocation;
/**
* 用于记录一条轨迹,包括起点、终点、轨迹中间点、距离、耗时、平均速度、时间
*/
public class PathRecord {
private AMapLocation mStartPoint;
private AMapLocation mEndPoint;
private List<AMapLocation> mPathLinePoints = new ArrayList<AMapLocation>();
private String mDistance;
private String mDuration;
private String mAveragespeed;
private String mDate;
private int mId = 0;
public int getId() {
return mId;
}
public void setId(int id) {
this.mId = id;
}
public AMapLocation getStartpoint() {
return mStartPoint;
}
public void setStartpoint(AMapLocation startpoint) {
this.mStartPoint = startpoint;
}
public AMapLocation getEndpoint() {
return mEndPoint;
}
public void setEndpoint(AMapLocation endpoint) {
this.mEndPoint = endpoint;
}
public List<AMapLocation> getPathline() {
return mPathLinePoints;
}
public void setPathline(List<AMapLocation> pathline) {
this.mPathLinePoints = pathline;
}
public String getDistance() {
return mDistance;
}
public void setDistance(String distance) {
this.mDistance = distance;
}
public String getDuration() {
return mDuration;
}
public void setDuration(String duration) {
this.mDuration = duration;
}
public String getAveragespeed() {
return mAveragespeed;
}
public void setAveragespeed(String averagespeed) {
this.mAveragespeed = averagespeed;
}
public String getDate() {
return mDate;
}
public void setDate(String date) {
this.mDate = date;
}
public void addpoint(AMapLocation point) {
mPathLinePoints.add(point);
}
@Override
public String toString() {
StringBuilder record = new StringBuilder();
record.append("recordSize:" + getPathline().size() + ", ");
record.append("distance:" + getDistance() + "m, ");
record.append("duration:" + getDuration() + "s");
return record.toString();
}
}
RecordAdapter.java
package com.application.locationpath;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class RecordAdapter extends BaseAdapter {
private final Context mContext;
private final List<PathRecord> mRecordList;
public RecordAdapter(Context context, List<PathRecord> list) {
this.mContext = context;
this.mRecordList = list;
}
@Override
public int getCount() {
return mRecordList.size();
}
@Override
public Object getItem(int position) {
return mRecordList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(mContext, R.layout.record_item, null);
holder.date = convertView.findViewById(R.id.date);
holder.record = convertView.findViewById(R.id.record);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
PathRecord item = mRecordList.get(position);
holder.date.setText(item.getDate());
holder.record.setText(item.toString());
return convertView;
}
private static class ViewHolder {
TextView date;
TextView record;
}
}
RecordActivity.java
package com.application.locationpath;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.amap.api.location.AMapLocation;
import com.amap.api.maps.MapsInitializer;
import java.util.ArrayList;
import java.util.List;
/**
* 所有轨迹list展示activity
*
*/
public class RecordActivity extends AppCompatActivity implements OnItemClickListener {
private RecordAdapter mAdapter;
private ListView mAllRecordListView;
private DbAdapter mDataBaseHelper;
private List<PathRecord> mAllRecord = new ArrayList<PathRecord>();
public static final String RECORD_ID = "record_id";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.record_list);
MapsInitializer.updatePrivacyShow(this,true,true);
MapsInitializer.updatePrivacyAgree(this,true);
mAllRecordListView = findViewById(R.id.recordlist);
mDataBaseHelper = new DbAdapter(this);
mDataBaseHelper.open();
searchAllRecordFromDB();
// if (list != null && list.size() > 0) {
// DbHelper = new DbAdapter(this);
// DbHelper.open();
// String duration = getDuration();
// float distance = getDistance(list);
// String average = getAverage(distance);
// String pathlineString = getPathLineString(list);
// AMapLocation firstLocation = list.get(0);
// AMapLocation lastLocation = list.get(list.size() - 1);
// String startpoint = amapLocationToString(firstLocation);
// String endpoint = amapLocationToString(lastLocation);
// 测试数据是否插入成功
mDataBaseHelper.createrecord("ass","ass","ass","ass","ass","ass","ass");
searchAllRecordFromDB();
// DbHelper.close();
// } else {
// Toast.makeText(MainActivity.this, "没有记录到路径", Toast.LENGTH_SHORT)
// .show();
// }
mAdapter = new RecordAdapter(this, mAllRecord);
mAllRecordListView.setAdapter(mAdapter);
mAllRecordListView.setOnItemClickListener(this);
}
private void searchAllRecordFromDB() {
mAllRecord = mDataBaseHelper.queryRecordAll();
}
public void onBackClick(View view) {
this.finish();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
PathRecord recorditem = (PathRecord) parent.getAdapter().getItem(
position);
Intent intent = new Intent(RecordActivity.this,
RecordShowActivity.class);
intent.putExtra(RECORD_ID, recorditem.getId());
startActivity(intent);
}
}
RecordShowActivity.java
package com.application.locationpath;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RadioButton;
import android.widget.Toast;
import android.widget.ToggleButton;
import androidx.appcompat.app.AppCompatActivity;
import com.amap.api.location.AMapLocation;
import com.amap.api.maps.AMap;
import com.amap.api.maps.AMap.OnMapLoadedListener;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.MapsInitializer;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.trace.LBSTraceClient;
import com.amap.api.trace.TraceListener;
import com.amap.api.trace.TraceLocation;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 实现轨迹回放、纠偏后轨迹回放
*
*/
public class RecordShowActivity extends AppCompatActivity implements
OnMapLoadedListener, TraceListener, OnClickListener {
private final static int AMAP_LOADED = 2;
private RadioButton mOriginRadioButton, mGraspRadioButton;
private ToggleButton mDisplaybtn;
private MapView mMapView;
private AMap mAMap;
private Marker mOriginStartMarker, mOriginEndMarker, mOriginRoleMarker;
private Marker mGraspStartMarker, mGraspEndMarker, mGraspRoleMarker;
private Polyline mOriginPolyline, mGraspPolyline;
private int mRecordItemId;
private List<LatLng> mOriginLatLngList;
private List<LatLng> mGraspLatLngList;
private boolean mGraspChecked = false;
private boolean mOriginChecked = true;
private ExecutorService mThreadPool;
private TraceRePlay mRePlay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.record_display_activity);
MapsInitializer.updatePrivacyShow(this,true,true);
MapsInitializer.updatePrivacyAgree(this,true);
mMapView = findViewById(R.id.map);
mMapView.onCreate(savedInstanceState);// 此方法必须重写
mGraspRadioButton = findViewById(R.id.record_show_activity_grasp_radio_button);
mOriginRadioButton = findViewById(R.id.record_show_activity_origin_radio_button);
mOriginRadioButton.setOnClickListener(this);
mGraspRadioButton.setOnClickListener(this);
mDisplaybtn = findViewById(R.id.displaybtn);
mDisplaybtn.setOnClickListener(this);
Intent recordIntent = getIntent();
int threadPoolSize = Runtime.getRuntime().availableProcessors() * 2 + 3;
mThreadPool = Executors.newFixedThreadPool(threadPoolSize);
if (recordIntent != null) {
mRecordItemId = recordIntent.getIntExtra(RecordActivity.RECORD_ID,
-1);
}
initMap();
}
private void initMap() {
if (mAMap == null) {
mAMap = mMapView.getMap();
mAMap.setOnMapLoadedListener(this);
}
}
private void startMove() {
if(mRePlay !=null){
mRePlay.stopTrace();
}
if (mOriginChecked) {
mRePlay = rePlayTrace(mOriginLatLngList, mOriginRoleMarker);
} else if (mGraspChecked) {
mRePlay = rePlayTrace(mGraspLatLngList, mGraspRoleMarker);
}
}
/**
* 轨迹回放方法
*/
private TraceRePlay rePlayTrace(List<LatLng> list, final Marker updateMarker) {
TraceRePlay replay = new TraceRePlay(list, 100,
new TraceRePlay.TraceRePlayListener() {
@Override
public void onTraceUpdating(LatLng latLng) {
if (updateMarker != null) {
updateMarker.setPosition(latLng); // 更新小人实现轨迹回放
}
}
@Override
public void onTraceUpdateFinish() {
mDisplaybtn.setChecked(false);
mDisplaybtn.setClickable(true);
}
});
mThreadPool.execute(replay);
return replay;
}
/**
* 将纠偏后轨迹小人设置到起点
*/
private void resetGraspRole() {
if (mGraspLatLngList == null) {
return;
}
LatLng startLatLng = mGraspLatLngList.get(0);
if (mGraspRoleMarker != null) {
mGraspRoleMarker.setPosition(startLatLng);
}
}
/**
* 将原始轨迹小人设置到起点
*/
private void resetOriginRole() {
if (mOriginLatLngList == null) {
return;
}
LatLng startLatLng = mOriginLatLngList.get(0);
if (mOriginRoleMarker != null) {
mOriginRoleMarker.setPosition(startLatLng);
}
}
@SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == AMAP_LOADED) {
try {
setupRecord();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
public void onBackClick(View view) {
this.finish();
if (mThreadPool != null) {
mThreadPool.shutdownNow();
}
}
public void onDestroy() {
super.onDestroy();
if (mThreadPool != null) {
mThreadPool.shutdownNow();
}
}
private LatLngBounds getBounds() {
LatLngBounds.Builder b = LatLngBounds.builder();
if (mOriginLatLngList == null) {
return b.build();
}
for (int i = 0; i < mOriginLatLngList.size(); i++) {
b.include(mOriginLatLngList.get(i));
}
return b.build();
}
/**
* 轨迹数据初始化
*/
private void setupRecord() throws Exception {
// 轨迹纠偏初始化
LBSTraceClient mTraceClient = new LBSTraceClient(
getApplicationContext());
DbAdapter dbhelper = new DbAdapter(this.getApplicationContext());
dbhelper.open();
PathRecord mRecord = dbhelper.queryRecordById(mRecordItemId);
dbhelper.close();
if (mRecord != null) {
List<AMapLocation> recordList = mRecord.getPathline();
AMapLocation startLoc = mRecord.getStartpoint();
AMapLocation endLoc = mRecord.getEndpoint();
if (recordList == null || startLoc == null || endLoc == null) {
return;
}
LatLng startLatLng = new LatLng(startLoc.getLatitude(),
startLoc.getLongitude());
LatLng endLatLng = new LatLng(endLoc.getLatitude(),
endLoc.getLongitude());
mOriginLatLngList = Util.parseLatLngList(recordList);
addOriginTrace(startLatLng, endLatLng, mOriginLatLngList);
List<TraceLocation> mGraspTraceLocationList = Util
.parseTraceLocationList(recordList);
// 调用轨迹纠偏,将mGraspTraceLocationList进行轨迹纠偏处理
mTraceClient.queryProcessedTrace(1, mGraspTraceLocationList,
LBSTraceClient.TYPE_AMAP, this);
}
}
/**
* 地图上添加原始轨迹线路及起终点、轨迹动画小人
*/
private void addOriginTrace(LatLng startPoint, LatLng endPoint,
List<LatLng> originList) {
mOriginPolyline = mAMap.addPolyline(new PolylineOptions().color(
Color.BLUE).addAll(originList));
mOriginStartMarker = mAMap.addMarker(new MarkerOptions().position(
startPoint).icon(
BitmapDescriptorFactory.fromResource(R.drawable.start)));
mOriginEndMarker = mAMap.addMarker(new MarkerOptions().position(
endPoint).icon(
BitmapDescriptorFactory.fromResource(R.drawable.end)));
try {
mAMap.moveCamera(CameraUpdateFactory.newLatLngBounds(getBounds(),50));
} catch (Exception e) {
e.printStackTrace();
}
mOriginRoleMarker = mAMap.addMarker(new MarkerOptions()
.position(startPoint)
.icon(BitmapDescriptorFactory.
fromBitmap(BitmapFactory
.decodeResource(
getResources(), R.drawable.walk))));
}
/**
* 设置是否显示原始轨迹
*/
private void setOriginEnable(boolean enable) {
mDisplaybtn.setClickable(true);
if (mOriginPolyline != null && mOriginStartMarker != null
&& mOriginEndMarker != null && mOriginRoleMarker != null) {
if (enable) {
mOriginPolyline.setVisible(true);
mOriginStartMarker.setVisible(true);
mOriginEndMarker.setVisible(true);
mOriginRoleMarker.setVisible(true);
} else {
mOriginPolyline.setVisible(false);
mOriginStartMarker.setVisible(false);
mOriginEndMarker.setVisible(false);
mOriginRoleMarker.setVisible(false);
}
}
}
/**
* 地图上添加纠偏后轨迹线路及起终点、轨迹动画小人
*/
private void addGraspTrace(List<LatLng> graspList, boolean mGraspChecked) {
if (graspList != null && graspList.size() >= 2) {
LatLng startPoint = graspList.get(0);
LatLng endPoint = graspList.get(graspList.size() - 1);
mGraspPolyline = mAMap.addPolyline(new PolylineOptions()
.setCustomTexture(
BitmapDescriptorFactory
.fromResource(R.drawable.grasp_trace_line))
.width(40).addAll(graspList));
mGraspStartMarker = mAMap.addMarker(new MarkerOptions().position(
startPoint).icon(
BitmapDescriptorFactory.fromResource(R.drawable.start)));
mGraspEndMarker = mAMap.addMarker(new MarkerOptions()
.position(endPoint).icon(
BitmapDescriptorFactory.fromResource(R.drawable.end)));
mGraspRoleMarker = mAMap.addMarker(new MarkerOptions().position(
startPoint).icon(
BitmapDescriptorFactory.fromBitmap(BitmapFactory
.decodeResource(getResources(), R.drawable.walk))));
if (!mGraspChecked) {
mGraspPolyline.setVisible(false);
mGraspStartMarker.setVisible(false);
mGraspEndMarker.setVisible(false);
mGraspRoleMarker.setVisible(false);
}
}
}
/**
* 设置是否显示纠偏后轨迹
*/
private void setGraspEnable(boolean enable) {
mDisplaybtn.setClickable(true);
if (mGraspPolyline != null && mGraspStartMarker != null
&& mGraspEndMarker != null && mGraspRoleMarker != null) {
if (enable) {
mGraspPolyline.setVisible(true);
mGraspStartMarker.setVisible(true);
mGraspEndMarker.setVisible(true);
mGraspRoleMarker.setVisible(true);
} else {
mGraspPolyline.setVisible(false);
mGraspStartMarker.setVisible(false);
mGraspEndMarker.setVisible(false);
mGraspRoleMarker.setVisible(false);
}
}
}
@Override
public void onMapLoaded() {
Message msg = handler.obtainMessage();
msg.what = AMAP_LOADED;
handler.sendMessage(msg);
}
/**
* 轨迹纠偏完成数据回调
*/
@Override
public void onFinished(int arg0, List<LatLng> list, int arg2, int arg3) {
addGraspTrace(list, mGraspChecked);
mGraspLatLngList = list;
}
@Override
public void onRequestFailed(int arg0, String arg1) {
Toast.makeText(this.getApplicationContext(), "轨迹纠偏失败:" + arg1,
Toast.LENGTH_SHORT).show();
}
@Override
public void onTraceProcessing(int arg0, int arg1, List<LatLng> arg2) {
}
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.displaybtn:
if (mDisplaybtn.isChecked()) {
startMove();
mDisplaybtn.setClickable(false);
}
break;
case R.id.record_show_activity_grasp_radio_button:
mGraspChecked = true;
mOriginChecked = false;
mGraspRadioButton.setChecked(true);
mOriginRadioButton.setChecked(false);
setGraspEnable(true);
setOriginEnable(false);
mDisplaybtn.setChecked(false);
resetGraspRole();
break;
case R.id.record_show_activity_origin_radio_button:
mOriginChecked = true;
mGraspChecked = false;
mGraspRadioButton.setChecked(false);
mOriginRadioButton.setChecked(true);
setGraspEnable(false);
setOriginEnable(true);
mDisplaybtn.setChecked(false);
resetOriginRole();
break;
}
}
}
MainActivity.java
package com.application.locationpath;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import androidx.appcompat.app.AppCompatActivity;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationClientOption.AMapLocationMode;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.MapView;
import com.amap.api.maps.MapsInitializer;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.trace.LBSTraceClient;
import com.amap.api.trace.TraceListener;
import com.amap.api.trace.TraceLocation;
import com.amap.api.trace.TraceOverlay;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class MainActivity extends AppCompatActivity implements LocationSource,
AMapLocationListener, TraceListener {
private MapView mMapView;
private AMap mAMap;
private OnLocationChangedListener mListener;
private AMapLocationClient mLocationClient;
private AMapLocationClientOption mLocationOption;
private PolylineOptions mPolyoptions;
private Polyline mpolyline;
private PathRecord record;
private long mStartTime;
private long mEndTime;
private ToggleButton btn; //状态按钮开关 turn on or turn off
private DbAdapter DbHelper;
private List<TraceLocation> mTracelocationlist = new ArrayList<TraceLocation>();
private List<TraceOverlay> mOverlayList = new ArrayList<TraceOverlay>();
private List<AMapLocation> recordList = new ArrayList<AMapLocation>();
private int traceSize = 30;
private int mDistance = 0;
private TraceOverlay mTraceOverlay; // 轨迹纠偏
private TextView mResultShow;
private Marker mlocMarker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.basic_map_activity);
MapsInitializer.updatePrivacyShow(this,true,true);
MapsInitializer.updatePrivacyAgree(this,true);
mMapView = findViewById(R.id.map);
mMapView.onCreate(savedInstanceState);// 此方法必须重写
init(); //初始化AMap对象
initpolyline();
}
private void init() {
if (mAMap == null) {
mAMap = mMapView.getMap();
setUpMap();
}
btn = findViewById(R.id.locationbtn);
btn.setOnClickListener(new OnClickListener() {
@SuppressLint("SetTextI18n")
@Override
public void onClick(View v) {
if (btn.isChecked()) {
mAMap.clear(true);
if (record != null) {
record = null;
}
record = new PathRecord();
mStartTime = System.currentTimeMillis();
record.setDate(getcueDate(mStartTime));
mResultShow.setText("总距离");
} else {
mEndTime = System.currentTimeMillis();
mOverlayList.add(mTraceOverlay);
DecimalFormat decimalFormat = new DecimalFormat("0.0");
mResultShow.setText(
decimalFormat.format(getTotalDistance() / 1000d) + "KM");
LBSTraceClient mTraceClient = null;
try {
mTraceClient = new LBSTraceClient(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
assert mTraceClient != null;
mTraceClient.queryProcessedTrace(2, Util.parseTraceLocationList(record.getPathline()) , LBSTraceClient.TYPE_AMAP, MainActivity.this);
saveRecord(record.getPathline(), record.getDate());
}
}
});
mResultShow = findViewById(R.id.show_all_dis);
mTraceOverlay = new TraceOverlay(mAMap);
}
protected void saveRecord(List<AMapLocation> list, String time) {
if (list != null && list.size() > 0) {
DbHelper = new DbAdapter(this);
DbHelper.open();
String duration = getDuration();
float distance = getDistance(list);
String average = getAverage(distance);
String pathlineString = getPathLineString(list);
AMapLocation firstLocation = list.get(0);
AMapLocation lastLocation = list.get(list.size() - 1);
String startpoint = amapLocationToString(firstLocation);
String endpoint = amapLocationToString(lastLocation);
DbHelper.createrecord(String.valueOf(distance), duration, average,
pathlineString, startpoint, endpoint, time);
DbHelper.close();
} else {
Toast.makeText(MainActivity.this, "没有记录到路径", Toast.LENGTH_SHORT)
.show();
}
}
private String getDuration() {
return String.valueOf((mEndTime - mStartTime) / 1000f);
}
private String getAverage(float distance) {
return String.valueOf(distance / (float) (mEndTime - mStartTime));
}
private float getDistance(List<AMapLocation> list) {
float distance = 0;
if (list == null || list.size() == 0) {
return distance;
}
for (int i = 0; i < list.size() - 1; i++) {
AMapLocation firstpoint = list.get(i);
AMapLocation secondpoint = list.get(i + 1);
LatLng firstLatLng = new LatLng(firstpoint.getLatitude(),
firstpoint.getLongitude());
LatLng secondLatLng = new LatLng(secondpoint.getLatitude(),
secondpoint.getLongitude());
double betweenDis;
betweenDis = AMapUtils.calculateLineDistance(firstLatLng,
secondLatLng);
distance = (float) (distance + betweenDis);
}
return distance;
}
private String getPathLineString(List<AMapLocation> list) {
if (list == null || list.size() == 0) {
return "";
}
StringBuffer pathline = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
AMapLocation location = list.get(i);
String locString = amapLocationToString(location);
pathline.append(locString).append(";");
}
String pathLineString = pathline.toString();
pathLineString = pathLineString.substring(0, pathLineString.length() - 1);
return pathLineString;
}
private String amapLocationToString(AMapLocation location) {
StringBuffer locString = new StringBuffer();
locString.append(location.getLatitude()).append(",");
locString.append(location.getLongitude()).append(",");
locString.append(location.getProvider()).append(",");
locString.append(location.getTime()).append(",");
locString.append(location.getSpeed()).append(",");
locString.append(location.getBearing());
return locString.toString();
}
private void initpolyline() {
mPolyoptions = new PolylineOptions();
mPolyoptions.width(10f);
mPolyoptions.color(Color.GRAY);
PolylineOptions tracePolytion = new PolylineOptions();
tracePolytion.width(40);
tracePolytion.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.grasp_trace_line));
}
/**
* 设置一些amap的属性
*/
private void setUpMap() {
mAMap.setLocationSource(this);// 设置定位监听
mAMap.getUiSettings().setMyLocationButtonEnabled(true);// 设置默认定位按钮是否显示
mAMap.setMyLocationEnabled(true);// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false
// 设置定位的类型为定位模式 ,可以由定位、跟随或地图根据面向方向旋转几种
mAMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);
}
/**
* 方法必须重写
*/
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mMapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
@Override
public void activate(OnLocationChangedListener listener) {
mListener = listener;
try {
startlocation();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void deactivate() {
mListener = null;
if (mLocationClient != null) {
mLocationClient.stopLocation();
mLocationClient.onDestroy();
}
mLocationClient = null;
}
/**
* 定位结果回调
* @param amapLocation 位置信息类
*/
@Override
public void onLocationChanged(AMapLocation amapLocation) {
if (mListener != null && amapLocation != null) {
if (amapLocation.getErrorCode() == 0) {
mListener.onLocationChanged(amapLocation);// 显示系统小蓝点
LatLng mylocation = new LatLng(amapLocation.getLatitude(),
amapLocation.getLongitude());
mAMap.moveCamera(CameraUpdateFactory.changeLatLng(mylocation));
if (btn.isChecked()) {
record.addpoint(amapLocation);
mPolyoptions.add(mylocation);
mTracelocationlist.add(Util.parseTraceLocation(amapLocation));
redrawline();
if (mTracelocationlist.size() > traceSize - 1) {
try {
trace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
} else {
String errText = "定位失败," + amapLocation.getErrorCode() + ": "
+ amapLocation.getErrorInfo();
Log.e("AmapErr", errText);
}
}
}
/**
* 开始定位。
*/
private void startlocation() throws Exception {
if (mLocationClient == null) {
mLocationClient = new AMapLocationClient(this);
mLocationOption = new AMapLocationClientOption();
// 设置定位监听
mLocationClient.setLocationListener(this);
// 设置为高精度定位模式
mLocationOption.setLocationMode(AMapLocationMode.Hight_Accuracy);
mLocationOption.setInterval(2000);
// 设置定位参数
mLocationClient.setLocationOption(mLocationOption);
mLocationClient.startLocation();
}
}
/**
* 实时轨迹画线
*/
private void redrawline() {
if (mPolyoptions.getPoints().size() > 1) {
if (mpolyline != null) {
mpolyline.setPoints(mPolyoptions.getPoints());
} else {
mpolyline = mAMap.addPolyline(mPolyoptions);
}
}
}
@SuppressLint("SimpleDateFormat")
private String getcueDate(long time) {
SimpleDateFormat formatter = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss ");
Date curDate = new Date(time);
String date = formatter.format(curDate);
final String date1 = date;
return date1;
}
public void record(View view) {
Intent intent = new Intent(MainActivity.this, RecordActivity.class);
startActivity(intent);
}
private void trace() throws Exception {
List<TraceLocation> locationList = new ArrayList<>(mTracelocationlist);
LBSTraceClient mTraceClient = new LBSTraceClient(getApplicationContext());
mTraceClient.queryProcessedTrace(1, locationList, LBSTraceClient.TYPE_AMAP, this);
TraceLocation lastlocation = mTracelocationlist.get(mTracelocationlist.size()-1);
mTracelocationlist.clear();
mTracelocationlist.add(lastlocation);
}
@Override
public void onRequestFailed(int i, String s) {
}
/**
* 轨迹纠偏失败回调。
*/
@Override
public void onTraceProcessing(int i, int i1, List<LatLng> list) {
}
/**
* 轨迹纠偏成功回调。
*/
@Override
public void onFinished(int lineID, List<LatLng> linepoints, int distance, int waitingtime) {
if (lineID == 1) {
if (linepoints != null && linepoints.size()>0) {
mTraceOverlay.add(linepoints);
mDistance += distance;
mTraceOverlay.setDistance(mTraceOverlay.getDistance()+distance);
if (mlocMarker == null) {
mlocMarker = mAMap.addMarker(new MarkerOptions().position(linepoints.get(linepoints.size() - 1))
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.point))
.title("距离:" + mDistance+"米"));
mlocMarker.showInfoWindow();
} else {
mlocMarker.setTitle("距离:" + mDistance+"米");
Toast.makeText(MainActivity.this, "距离"+mDistance, Toast.LENGTH_SHORT).show();
mlocMarker.setPosition(linepoints.get(linepoints.size() - 1));
mlocMarker.showInfoWindow();
}
}
} else if (lineID == 2) if (linepoints != null && linepoints.size() > 0) {
mAMap.addPolyline(new PolylineOptions()
.color(Color.RED)
.width(40).addAll(linepoints));
}
}
/**
* 最后获取总距离
*/
private int getTotalDistance() {
int distance = 0;
for (TraceOverlay to : mOverlayList) {
distance = distance + to.getDistance();
}
return distance;
}
}
TraceRePlay.java
package com.application.locationpath;
import java.lang.ref.WeakReference;
import java.util.List;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import com.amap.api.maps.model.LatLng;
/**
* 轨迹回放工具类
*
*/
public class TraceRePlay implements Runnable {
private TraceRePlayHandler mTraceHandler;
private static final int TRACE_MOVE = 1;
private static final int TRACE_FINISH = 2;
private List<LatLng> mTraceList;
private int mIntervalMillisecond;
private TraceRePlayListener mTraceUpdateListener;
private boolean mStop = false;
/**
* 构造轨迹回放需要,List、时间间隔、回调listener
*
* @param list
* 轨迹list
* @param intervalMillisecond
* 回调时间间隔
* @param listener
* 回调listener
*/
public TraceRePlay(List<LatLng> list, int intervalMillisecond,
TraceRePlayListener listener) {
mTraceList = list;
mIntervalMillisecond = intervalMillisecond;
mTraceUpdateListener = listener;
mTraceHandler = new TraceRePlayHandler(this);
}
public void stopTrace() {
mStop = true;
}
/**
* 接收run发送的消息,达到按照设定时间间隔轮巡轨迹list目的
*
*/
static class TraceRePlayHandler extends Handler {
WeakReference<TraceRePlay> mTraceRePlay;
public TraceRePlayHandler(TraceRePlay traceRePlay) {
super(Looper.getMainLooper());
mTraceRePlay = new WeakReference<TraceRePlay>(traceRePlay);
}
@Override
public void handleMessage(Message message) {
super.handleMessage(message);
TraceRePlay trace = mTraceRePlay.get();
switch (message.what) {
case TRACE_MOVE:
LatLng latLng = (LatLng) message.obj;
if (trace.mTraceUpdateListener != null) {
trace.mTraceUpdateListener.onTraceUpdating(latLng);
}
break;
case TRACE_FINISH:
if (trace.mTraceUpdateListener != null) {
trace.mTraceUpdateListener.onTraceUpdateFinish();
}
break;
default:
break;
}
}
}
public interface TraceRePlayListener {
// 轨迹回放过程回调
void onTraceUpdating(LatLng latLng);
//轨迹回放结束回调
void onTraceUpdateFinish();
}
/**
* 将 mTraceList 按照给定的时间间隔和次序发消息给TraceRePlayHandler以达到轨迹回放效果
*/
@Override
public void run() {
if (mTraceList != null) {
for (int i = 0; i < mTraceList.size(); i++) {
if (mStop) {
break;
}
LatLng latLng = mTraceList.get(i);
Message message = mTraceHandler.obtainMessage();
message.what = TRACE_MOVE;
message.obj = latLng;
mTraceHandler.sendMessage(message);
try {
Thread.sleep(mIntervalMillisecond);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!mStop) {
Message finishMessage = mTraceHandler.obtainMessage();
finishMessage.what = TRACE_FINISH;
mTraceHandler.sendMessage(finishMessage);
}
}
}
}
android studio的版本不同,盲目搬用的话可能会出现许多问题,大家一定要看看我的版本哦!
我的android版本:11.0.12
我的gradle版本:7.3.3
我的jdk版本:1.8
内容挺多的哈,大家要有耐心哦!!!需要安装包的话评论区私我即可!