高德地图定位、足迹跟踪,轨迹记录复现【2023年】

效果图:

 这个操作是,先开启手机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代码:

目录

效果图:

 导入的各类包如下图1、2所示:

manifest.xml【添加一些必要的权限】

build.gradle(:app) 添加依赖

java代码:

DbAdapter.java

Util 工具类不可少:

EmulatorService.java

PathRecord.java

RecordAdapter.java

RecordActivity.java

RecordShowActivity.java

MainActivity.java

TraceRePlay.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

内容挺多的哈,大家要有耐心哦!!!需要安装包的话评论区私我即可!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶灼hua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值