添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

高德地图绘制轨迹和通过经纬度转屏幕坐标绘制轨迹(一)

4 个月前 · 来自专栏 安卓开发笔记

效果图:

1. 高德地图MapView中绘制轨迹

2. 通过经纬度转屏幕坐标自定义MyMapView中绘制轨迹


上代码:

manifest.xml中添加权限

<!-- 6.0以上需要申请动态权限activity中自行申请, 高德地图SDK自行配置此处省略 -->
<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_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

build.gradle(app)中添加SDK依赖

// 倒计时
implementation 'in.xiandan:count-down-timer:1.0.3'
// 高德地图相关
implementation 'com.amap.api:3dmap:latest.integration'
implementation 'com.amap.api:location:latest.integration'

注意: 由于国家最新出台用户个人隐私相关整改权限政策, 高德地图使用, 推荐在用户APP界面明确同意(点击事件)使用APP协议后, 添加如下接口:

//设置高德地图权限
MapsInitializer.updatePrivacyShow(this,true,true);
MapsInitializer.updatePrivacyAgree(this,true);

(一)高德地图MapView中绘制轨迹:

需要自己创建数据库存取GPS数据, 此处省略...

1) 实时绘制轨迹并保存GPS数据到本地数据库

SportsGDActivity.java

package com.yangsion.test.activity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.SystemClock;
import android.speech.tts.TextToSpeech;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Chronometer;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
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.MapView;
import com.amap.api.maps.model.BitmapDescriptor;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.MyLocationStyle;
import com.amap.api.maps.model.Polyline;
import com.amap.api.maps.model.PolylineOptions;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.yangsion.test.R;
import com.yangsion.test.application.SmuuApplication;
import com.yangsion.test.db.SQLiteUtil;
import com.yangsion.test.en.SportsMoveDataEn;
import com.yangsion.test.en.SportsNumDataEn;
import com.yangsion.test.util.LogUtils;
import com.yangsion.test.util.SimpleDateFormatUtil;
import com.yangsion.test.util.SystemUtil;
import com.yangsion.test.util.UnitConvertUtil;
import com.yangsion.test.view.CircleBarView;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Calendar;
import java.util.Locale;
import in.xiandan.countdowntimer.CountDownTimerSupport;
import in.xiandan.countdowntimer.OnCountDownTimerListener;
 * 运动 高德地图
public class SportsGDActivity extends BaseActivity implements View.OnClickListener, View.OnLongClickListener {
    private FloatingActionButton mHistory;
    private TextView mTemrTxt;
    private LinearLayout mMapLayout;
    private LinearLayout mMixInfo;
    private LinearLayout mMaxInfo;
    private RelativeLayout mLockTrueBtnLayout;
    private LinearLayout mAllBtnLayout;
    private RelativeLayout mStartLayout;
    private RelativeLayout mLockBtnLayout;
    private RelativeLayout mStopBtnLayout;
    private RelativeLayout mPauseBtnLayout;
    private RelativeLayout mStartBtnLayout;
    private RelativeLayout mVoiceBtnLayout;
    private MapView mGdMap;
    private ImageButton mMaxDrawer;
    private TextView mGpsDesc;
    private TextView mGpsStatusDesc;
    private TextView mDistance;
    private TextView mDistanceUnit;
    private Chronometer mRunTime;
    private TextView mPace;
    private TextView mStepNum;
    private TextView mCalories;
    private ImageButton mLockTrue;
    private CircleBarView mProgressBarLock;
    private CircleBarView mProgressBarStop;
    private ImageButton mLock;
    private ImageButton mPause;
    private ImageButton mStop;
    private ImageButton mStart;
    private ImageButton mVoice;
    private ImageButton mMixDrawer;
    private TextView mDistance2;
    private TextView mRunNumUnit2;
    private Chronometer mRunTime2;
    private ImageView mGpsSignal0;
    private ImageView mGpsSignal1;
    private ImageView mGpsSignal2;
    private ImageView mGpsSignal3;
    private ImageView[] gpsImgs;
    private MyLocationStyle myLocationStyle;
    private AMap gd_aMap = null;
    //声明AMapLocationClient类对象
    public AMapLocationClient mLocationClient = null;
    //声明AMapLocationClientOption对象
    public AMapLocationClientOption mLocationOption = null;
    //绘制实线的内容
    public PolylineOptions mPolylineOptions = null;
    //绘制虚线的内容
    public PolylineOptions mPolylineOptions2 = null;
    //绘制marker内容
    public MarkerOptions markerOptions = null;
    public TextToSpeech mTextToSpeech = null;
    private LatLng oldLatLng = null;
    private String dviceMac = "";
    private String userId = "";
    private String weight = "";
    private String startTime = "";
    private String sportMode = "1";// 运动类型 0-walk,1-run,2-swim,3-riding,4-triathlon(铁人三项)
    private String sportsDatas = "";
    private CountDownTimerSupport mTimer = new CountDownTimerSupport(3000, 1000);
    private long mPauseTime = 0;
    private boolean isOpenVoice = false;
    private boolean isPause = false;
    private float distanceAll = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sports_gd);
        initTTS();
        initView(savedInstanceState);
        initData();
    @Override
    protected void onResume() {
        super.onResume();
        mGdMap.onResume();
    @Override
    protected void onPause() {
        super.onPause();
        mGdMap.onPause();
        //moveTaskToBack(true);//在后台运行
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mGdMap.onDestroy();
        mLocationClient.onDestroy();//销毁定位客户端,同时销毁本地定位服务。
        mTextToSpeech.stop(); // 不管是否正在朗读TTS都被打断
        mTextToSpeech.shutdown(); // 关闭,释放资源
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        mGdMap.onSaveInstanceState(outState);
    private void initView(Bundle savedInstanceState) {
        //获取地图控件引用
        mGdMap = (MapView) findViewById(R.id.gd_map);
        //在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图
        mGdMap.onCreate(savedInstanceState);
        mGpsDesc = (TextView) findViewById(R.id.gps_desc);
        mGpsDesc.setOnClickListener(this);
        mGpsStatusDesc = (TextView) findViewById(R.id.gps_status_desc);
        mGpsStatusDesc.setOnClickListener(this);
        mHistory = (FloatingActionButton) findViewById(R.id.history);
        mHistory.setOnClickListener(this);
        mTemrTxt = (TextView) findViewById(R.id.temrTxt);
        mMapLayout = (LinearLayout) findViewById(R.id.mapLayout);
        mStartLayout = (RelativeLayout) findViewById(R.id.startLayout);
        mTimer.start();
        mTimer.setOnCountDownTimerListener(mOnCountDownTimerListener);
        mMaxDrawer = (ImageButton) findViewById(R.id.maxDrawer);
        mMaxDrawer.setOnClickListener(this);
        mDistance = (TextView) findViewById(R.id.distance);
        mDistance.setOnClickListener(this);
        mDistanceUnit = (TextView) findViewById(R.id.distanceUnit);
        mDistanceUnit.setOnClickListener(this);
        mRunTime = (Chronometer) findViewById(R.id.runTime);
        mRunTime.setOnClickListener(this);
        mPace = (TextView) findViewById(R.id.pace);
        mPace.setOnClickListener(this);
        mStepNum = (TextView) findViewById(R.id.step_num);
        mStepNum.setOnClickListener(this);
        mCalories = (TextView) findViewById(R.id.calories);
        mCalories.setOnClickListener(this);
        mLockTrue = (ImageButton) findViewById(R.id.lock_true);
        mLockTrue.setOnClickListener(this);
        mLockTrue.setOnLongClickListener(this);
        mLock = (ImageButton) findViewById(R.id.lock);
        mLock.setOnClickListener(this);
        mProgressBarLock = (CircleBarView) findViewById(R.id.progressBarLock);
        mProgressBarLock.setOnClickListener(this);
        mPause = (ImageButton) findViewById(R.id.pause);
        mPause.setOnClickListener(this);
        mProgressBarStop = (CircleBarView) findViewById(R.id.progressBarStop);
        mProgressBarStop.setOnClickListener(this);
        mStop = (ImageButton) findViewById(R.id.stop);
        mStop.setOnClickListener(this);
        mStop.setOnLongClickListener(this);
        mStart = (ImageButton) findViewById(R.id.start);
        mStart.setOnClickListener(this);
        mVoice = (ImageButton) findViewById(R.id.voice);
        mVoice.setOnClickListener(this);
        mMaxInfo = (LinearLayout) findViewById(R.id.maxInfo);
        mMaxInfo.setOnClickListener(this);
        mMixDrawer = (ImageButton) findViewById(R.id.mixDrawer);
        mMixDrawer.setOnClickListener(this);
        mDistance2 = (TextView) findViewById(R.id.distance2);
        mDistance2.setOnClickListener(this);
        mRunNumUnit2 = (TextView) findViewById(R.id.runNumUnit2);
        mRunNumUnit2.setOnClickListener(this);
        mRunTime2 = (Chronometer) findViewById(R.id.runTime2);
        mRunTime2.setOnClickListener(this);
        mMixInfo = (LinearLayout) findViewById(R.id.mixInfo);
        mMixInfo.setOnClickListener(this);
        mGpsSignal0 = (ImageView) findViewById(R.id.gps_signal0);
        mGpsSignal1 = (ImageView) findViewById(R.id.gps_signal1);
        mGpsSignal2 = (ImageView) findViewById(R.id.gps_signal2);
        mGpsSignal3 = (ImageView) findViewById(R.id.gps_signal3);
        gpsImgs = new ImageView[]{mGpsSignal0, mGpsSignal1, mGpsSignal2, mGpsSignal3};
        mLockTrueBtnLayout = (RelativeLayout) findViewById(R.id.lock_true_btn_layout);
        mLockTrueBtnLayout.setOnClickListener(this);
        mAllBtnLayout = (LinearLayout) findViewById(R.id.all_btn_layout);
        mAllBtnLayout.setOnClickListener(this);
        mLockBtnLayout = (RelativeLayout) findViewById(R.id.lock_btn_layout);
        mLockBtnLayout.setOnClickListener(this);
        mStopBtnLayout = (RelativeLayout) findViewById(R.id.stop_btn_Layout);
        mStopBtnLayout.setOnClickListener(this);
        mPauseBtnLayout = (RelativeLayout) findViewById(R.id.pause_btn_Layout);
        mPauseBtnLayout.setOnClickListener(this);
        mStartBtnLayout = (RelativeLayout) findViewById(R.id.start_btn_Layout);
        mStartBtnLayout.setOnClickListener(this);
        mVoiceBtnLayout = (RelativeLayout) findViewById(R.id.voice_btn_layout);
        mVoiceBtnLayout.setOnClickListener(this);
    private void initData() {
        //异常断点记录不为空, 继续记录数据
        sportsDatas = SmuuApplication.getApplication().getSportsDatas();
        startTime = SimpleDateFormatUtil.Y_MM_ddHHmmss().format(Calendar.getInstance().getTime());
        dviceMac = SmuuApplication.getApplication().getConnectDevice();
        userId = SmuuApplication.getApplication().getUserAccount();
        weight = SmuuApplication.getApplication().getUserEn().weight;
        if (!sportsDatas.equals("")) {
            LogUtils.d("gy", "sportsDatas: " + sportsDatas);
            String[] split = sportsDatas.split(",");
            startTime = split[1];
            mDistance.setText(split[3]);
            mDistance2.setText(split[3]);
            distanceAll = Float.parseFloat(split[3]);
            mCalories.setText(split[4]);
            mStepNum.setText(split[5]);
            mRunTime.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
                @Override
                public void onChronometerTick(Chronometer chronometer) {
                    //LogUtils.d("gy", "chronometer: " + chronometer.getBase());
                    //保存最新记录, 异常情况重新进入, 继续从断点记录
                    String sportsDatas = sportMode + "," + startTime + "," +
                            String.valueOf(SystemClock.elapsedRealtime() - mRunTime.getBase()) + "," + split[3] + "," +
                            split[4] + "," + split[5];
                    SmuuApplication.getApplication().setSportsDatas(sportsDatas);
        initVoiceState();
        if (gd_aMap == null) {
            gd_aMap = mGdMap.getMap();
        myLocationStyle = new MyLocationStyle();//初始化定位蓝点样式类
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。(1秒1次定位)如果不设置myLocationType,默认也会执行此种模式。
        myLocationStyle.interval(2000); //设置连续定位模式下的定位间隔,只在连续定位模式下生效,单次定位模式下不会生效。单位为毫秒。
        //自定义蓝点icon
        myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.drawable.ic_line_head));//注意: 需要png图片
        myLocationStyle.strokeColor(Color.parseColor("#00000000"));//设置定位蓝点精度圆圈的边框颜色的方法。
        myLocationStyle.strokeWidth(2f);//设置定位蓝点精度圈的边框宽度的方法。
        myLocationStyle.radiusFillColor(Color.parseColor("#00000000"));//设置定位蓝点精度圆圈的填充颜色的方法。
        myLocationStyle.showMyLocation(true);
        //gd_aMap.setLocationSource(this);// 设置定位资源
        gd_aMap.setMyLocationStyle(myLocationStyle);//设置定位蓝点的Style
        //gd_aMap.getUiSettings().setMyLocationButtonEnabled(true);设置默认定位按钮是否显示,非必需设置。
        gd_aMap.setMyLocationEnabled(true);// 设置为true表示启动显示定位蓝点,false表示隐藏定位蓝点并不进行定位,默认是false。
        // 缩放级别(zoom):地图缩放级别范围为【4-20级】,值越大地图越详细
        gd_aMap.moveCamera(CameraUpdateFactory.zoomTo(18));
        gd_aMap.getUiSettings().setZoomControlsEnabled(false);//去掉地图右下角隐藏的缩放按钮
        //gd_aMap.setOnMyLocationChangeListener(myLocationChangeListener);//3D
        try {
            mLocationClient = new AMapLocationClient(getApplicationContext());
        } catch (Exception e) {
            LogUtils.e("gye", "AMapLocationClient Exception: " + e.getMessage());
            e.printStackTrace();
//        //设置定位回调监听
//        mLocationClient.setLocationListener(mLocationListener);
        //初始化AMapLocationClientOption对象
        mLocationOption = new AMapLocationClientOption();
        //设置定位模式为AMapLocationMode.Hight_Accuracy,高精度模式。
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//        //设置定位模式为AMapLocationMode.Battery_Saving,低功耗模式。
//        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);
//        //设置定位模式为AMapLocationMode.Device_Sensors,仅设备模式。
//        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Device_Sensors);
        //设置定位场景,目前支持三种场景(签到、出行、运动,默认无场景)
        mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Sport);
        if (null != mLocationOption) {
            mLocationClient.setLocationOption(mLocationOption);
            //设置场景模式后最好调用一次stop,再调用start以保证场景模式生效
            mLocationClient.stopLocation();
            mLocationClient.startLocation();
        //设置绘制线的宽度和颜色
        mPolylineOptions = new PolylineOptions().width(10).color(Color.GREEN);
        mPolylineOptions2 = new PolylineOptions().setDottedLine(true).width(10).color(Color.GRAY);
        markerOptions = new MarkerOptions();
        markerOptions.title("start location");
        markerOptions.visible(true);
        BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_starting_point));
        markerOptions.icon(bitmapDescriptor);
    private void initVoiceState() {
        isOpenVoice = SmuuApplication.getApplication().isOpenVoice();
        if (isOpenVoice) {
            mVoice.setBackgroundResource(R.drawable.ic_voice);
        } else {
            mVoice.setBackgroundResource(R.drawable.ic_not_voice);
    @Override
    public void onClick(View v) {
        if (v == mHistory) {
            startActivity(this, SportsRecordActivity.class, Intent.FLAG_ACTIVITY_SINGLE_TOP, false);
        } else if (v == mMaxDrawer) {//向下隐藏
            mMaxInfo.setVisibility(View.GONE);
            mMixInfo.setVisibility(View.VISIBLE);
        } else if (v == mMixDrawer) {//向上展示
            mMixInfo.setVisibility(View.GONE);
            mMaxInfo.setVisibility(View.VISIBLE);
        } else if (v == mLockTrue) {
            showToast(R.string.activity_sports_longtouch_unlock);
        } else if (v == mLock) {
            mLockTrueBtnLayout.setVisibility(View.VISIBLE);
            mAllBtnLayout.setVisibility(View.GONE);
        } else if (v == mStop) {
            showToast(R.string.activity_sports_longtouch_over);
        } else if (v == mPause) {
            isPause = true;
            mStopBtnLayout.setVisibility(View.VISIBLE);
            mStartBtnLayout.setVisibility(View.VISIBLE);
            mPauseBtnLayout.setVisibility(View.GONE);
            mRunTime.stop();
            mRunTime2.stop();
            mRunTime2.setText(mRunTime.getText());
            mPauseTime = SystemClock.elapsedRealtime() - mRunTime.getBase();
            //LogUtils.i("gy", "mPauseTime: " + mPauseTime);
            //LogUtils.i("gy", "sportsTime: " + (SystemClock.elapsedRealtime() - mPauseTime));
        } else if (v == mStart) {
            isPause = false;
            mStopBtnLayout.setVisibility(View.GONE);
            mStartBtnLayout.setVisibility(View.GONE);
            mPauseBtnLayout.setVisibility(View.VISIBLE);
            mRunTime.setBase(SystemClock.elapsedRealtime() - mPauseTime);
            mRunTime2.setBase(mRunTime.getBase());
            mRunTime.start();
            mRunTime2.start();
        } else if (v == mVoice) {
            if (isOpenVoice) {
                isOpenVoice = false;
                SmuuApplication.getApplication().setOpenVoice(isOpenVoice);
                mVoice.setBackgroundResource(R.drawable.ic_not_voice);
            } else {
                isOpenVoice = true;
                SmuuApplication.getApplication().setOpenVoice(isOpenVoice);
                mVoice.setBackgroundResource(R.drawable.ic_voice);
    public long startTimeSS = 0;
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onLongClick(View v) {
        startTimeSS = System.currentTimeMillis();
        if (v == mLockTrue) {// 解锁
            mProgressBarLock.setVisibility(View.VISIBLE);
            mProgressBarLock.setMaxNum(360f);
            mProgressBarLock.setProgressNum(360f, 1500);
            mProgressBarLock.setOnAnimationEndListener(new CircleBarView.OnAnimationEndListener() {
                @Override
                public void onAnimationEnd() {
                    if (mProgressBarLock.getProgressNum() == 360f) {
                        mAllBtnLayout.setVisibility(View.VISIBLE);
                        mLockTrueBtnLayout.setVisibility(View.GONE);
                    mProgressBarLock.setVisibility(View.INVISIBLE);
            mLockTrue.setOnTouchListener((v1, event) -> {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_UP:
                        int end = (int) ((System.currentTimeMillis() - startTimeSS) / 1000);
                        //LogUtils.e("gy", "time SS: " + end);
                        if (end == 3) {
                            mProgressBarLock.setVisibility(View.INVISIBLE);
                            mAllBtnLayout.setVisibility(View.VISIBLE);
                            mLockTrueBtnLayout.setVisibility(View.GONE);
                        } else {
                            mProgressBarLock.setProgressNum(0f, 600);
                        break;
                return false;
            return true;
        } else if (v == mStop) {// 停止运动
            mProgressBarStop.setVisibility(View.VISIBLE);
            mProgressBarStop.setMaxNum(360f);
            mProgressBarStop.setProgressNum(360f, 1500);
            mProgressBarStop.setOnAnimationEndListener(new CircleBarView.OnAnimationEndListener() {
                @Override
                public void onAnimationEnd() {
                    if (mProgressBarStop.getProgressNum() == 360f) {
                        saveSportsData();
                    mProgressBarStop.setVisibility(View.INVISIBLE);
            mStop.setOnTouchListener((v1, event) -> {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_UP:
                        int end = (int) ((System.currentTimeMillis() - startTimeSS) / 1000);
                        if (end == 3) {
                            mProgressBarStop.setVisibility(View.INVISIBLE);
                        } else {
                            mProgressBarStop.setProgressNum(0f, 600);
                        break;
                return false;
            return true;
        return false;
     * 保存运动数据
    public void saveSportsData() {
        SQLiteUtil sqLiteUtil = new SQLiteUtil(getApplicationContext());
        if (distanceAll <= 0) {//距离为0 删除这条运动数据
            LogUtils.e("gy", "distanceAll == 0");
            sqLiteUtil.SqlDelete("sportsdata", "date", new String[]{startTime});
        } else {
//                List<SportsMoveDataEn> allSportsData = sqLiteUtil.getAllSportsData();
//                for (SportsMoveDataEn en : allSportsData) {
//                    LogUtils.d("gy", "startTime :" + en.startTime);
//                    LogUtils.d("gy", "sportsTime :" + en.sportsTime);
//                    LogUtils.d("gy", "distance :" + en.distance);
//                    LogUtils.d("gy", "calories :" + en.calories);
//                    LogUtils.d("gy", "lat :" + en.lat);
//                    LogUtils.d("gy", "lng :" + en.lng);
//                }
            //运动停止后, 记录这次运动数据, 如果逻辑没有走到这里, 则为异常情况,
            //当重新打开此界面或进入APP进行判断, 在运动时被中断, 继续进入界面进行运动计算.
            String sportsDatas = SmuuApplication.getApplication().getSportsDatas();
            if (!sportsDatas.equals("")) {
                //String 组拼顺序
                //sportsDatas = "sportMode,startTime,sportsTime,distanceStr,aloriesStr,stepNum";
                String[] split = sportsDatas.split(",");
                SportsNumDataEn dataEn = new SportsNumDataEn();
                dataEn.user = userId;
                dataEn.deviceId = dviceMac;
                dataEn.deviceType = "0";//0手机,1手表  判断数据是否从手表来的
                dataEn.index = "-1";
                dataEn.sportMode = split[0];
                dataEn.startTime = split[1];
                dataEn.sportsTime = split[2];
                dataEn.pace = "0";//每条记录的平均值
                dataEn.stepFreq = "0";//等于总步数 / 总用时
                dataEn.distance = split[3];
                dataEn.calories = split[4];
                dataEn.stepNum = split[5];
                dataEn.speed = "0";//每小时速度 = 总距离 / 总用时(分钟) * 60
                sqLiteUtil.saveSportsNumData(dataEn);
        SmuuApplication.getApplication().setSportsDatas("");//正常完成运动数据记录,重置为空
        finish();
    private int index = 0;//监听回调次数
    private float oldRunTime = 0;//第一次定位的时间
    private float allStep = 0;//累计步数
    //声明定位回调监听器
    public AMapLocationListener mLocationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation aMapLocation) {
            if (aMapLocation != null) {
                // 定位精度
                float accuracy = aMapLocation.getAccuracy();
                // 海拔
                double altitude = aMapLocation.getAltitude();
                // GPS信号状态: 强,弱,未知
                int gpsStatus = aMapLocation.getGpsAccuracyStatus();
//                LogUtils.i("gy", "accuracy: " + accuracy);
//                LogUtils.i("gy", "altitude: " + altitude);
//                LogUtils.i("gy", "gpsStatus: " + gpsStatus);
                LatLng newLatLng = new LatLng(aMapLocation.getLatitude(), aMapLocation.getLongitude());
                if (oldLatLng == null) {
                    LogUtils.i("gy", "oldLatLng is null");
                    if (newLatLng.latitude != 0 && newLatLng.longitude != 0) {//经纬度不为0, 才记录
                        markerOptions.position(newLatLng);
                        gd_aMap.addMarker(markerOptions);
                        //第一次定位位置
                        oldLatLng = newLatLng;
                        //保存到数据库
                        SQLiteUtil sqLiteUtil = new SQLiteUtil(getApplicationContext());
                        SportsMoveDataEn smdEn = new SportsMoveDataEn();
                        smdEn.user = userId.equals("") ? "000000" : userId;
                        smdEn.deviceId = dviceMac.equals("1") ? "000000" : dviceMac;
                        smdEn.sportMode = sportMode;
                        smdEn.startTime = startTime;
                        smdEn.sportsTime = "0";
                        smdEn.distance = "0";
                        smdEn.calories = "0";
                        smdEn.stepNum = "0";
                        smdEn.stepFreq = "0";
                        smdEn.heartRate = "0";
                        smdEn.speed = "0";
                        smdEn.pace = "0";
                        smdEn.pa = "0";
                        smdEn.altitude = "0";
                        smdEn.lat = String.valueOf(newLatLng.latitude);
                        smdEn.lng = String.valueOf(newLatLng.longitude);
                        sqLiteUtil.saveSportsData(smdEn);
                if (gpsStatus == AMapLocation.GPS_ACCURACY_UNKNOWN) {
                    mGpsStatusDesc.setVisibility(View.VISIBLE);
                    mGpsStatusDesc.setText(R.string.activity_sport_gps_status_no);
                    for (int i = 0; i < gpsImgs.length; i++) {
                        gpsImgs[i].setBackgroundColor(getColor(R.color.gray));
                    // 没有GPS信号, 使用传感器
                    //设置定位模式为AMapLocationMode.Device_Sensors,仅设备模式。
                    mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Device_Sensors);
                    //设置运动场景
                    mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Sport);
                    //给定位客户端对象设置定位参数
                    mLocationClient.setLocationOption(mLocationOption);
                    mLocationClient.stopLocation();
                    mLocationClient.startLocation();
                    mPace.setText("- -");
                } else {// 有GPS信号
                    //设置定位模式为AMapLocationMode.Device_Sensors,高精度模式。
                    mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
                    //设置运动场景
                    mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Sport);
                    //给定位客户端对象设置定位参数
                    mLocationClient.setLocationOption(mLocationOption);
                    mLocationClient.stopLocation();
                    mLocationClient.startLocation();
                    // 有信号情况
                    if (gpsStatus == AMapLocation.GPS_ACCURACY_BAD) {// GPS信号弱
                        mGpsStatusDesc.setVisibility(View.VISIBLE);
                        mGpsStatusDesc.setText(R.string.activity_sport_gps_status_0);
                        for (int i = 0; i < gpsImgs.length; i++) {
                            if (i < 1) {
                                gpsImgs[i].setBackgroundColor(getColor(R.color.orangered));
                            } else {
                                gpsImgs[i].setBackgroundColor(getColor(R.color.gray));
                    } else if (gpsStatus == AMapLocation.GPS_ACCURACY_GOOD) {// GPS信号强
                        mGpsStatusDesc.setVisibility(View.GONE);
                        for (int i = 0; i < gpsImgs.length; i++) {
                            if (accuracy <= 10) {// 精度10米
                                gpsImgs[i].setBackgroundColor(getColor(R.color.orangered));
                            } else if (accuracy > 10 && accuracy <= 30) {
                                if (i < 2) {
                                    gpsImgs[i].setBackgroundColor(getColor(R.color.orangered));
                                } else {
                                    gpsImgs[i].setBackgroundColor(getColor(R.color.gray));
                            } else if (accuracy > 30) {
                                mGpsStatusDesc.setVisibility(View.VISIBLE);
                                mGpsStatusDesc.setText(R.string.activity_sport_gps_status_1_low);
                                if (i < 1) {
                                    gpsImgs[i].setBackgroundColor(getColor(R.color.orangered));
                                } else {
                                    gpsImgs[i].setBackgroundColor(getColor(R.color.gray));
                if (!isPause) {//未点击暂停, 正常记录与绘制
                    //绘制路线
                    if (index % 2 == 0) {//监听每回调2次, 进入判断绘制一次
                        if (aMapLocation.getLatitude() > 0 && aMapLocation.getLongitude() > 0) {
                            if (oldLatLng.latitude != newLatLng.latitude || oldLatLng.longitude != newLatLng.longitude) {
                                // 精度20米内或者无GPS信号仅设备传感器模式, 绘制并保存数据
                                if (accuracy <= 20 || mLocationOption.getLocationMode().equals(AMapLocationClientOption.AMapLocationMode.Device_Sensors)) {
                                    float lineDistance = AMapUtils.calculateLineDistance(oldLatLng, newLatLng);//米
                                    //LogUtils.e("gy", "lineDistance: " + lineDistance);
                                    // 跑步移动的速度每4秒不超过40米, 超过不记录
                                    if (lineDistance > 0 && lineDistance < 40) {
                                        mPolylineOptions.color(Color.GREEN);
                                        mPolylineOptions.setDottedLine(false);// 不为虚线,实线
                                        mPolylineOptions.add(oldLatLng, newLatLng);
                                        Polyline polyline = gd_aMap.addPolyline(mPolylineOptions);
                                        //计算距离
                                        float old_distance = lineDistance / 1000;//公里
                                        distanceAll += old_distance;
                                        String distanceStr = String.format(Locale.ENGLISH, "%.2f", distanceAll);
                                        DecimalFormat df = new DecimalFormat("0.00", new DecimalFormatSymbols(Locale.ENGLISH));
                                        int drinkType = SmuuApplication.getApplication().getDrinkType(SmuuApplication.getApplication().UNIT);
                                        String distance = df.format(Double.parseDouble(distanceStr));
                                        if (drinkType == 0) {// 公制
                                            mDistanceUnit.setText(R.string.activity_target_run_km);
                                        } else {// 英制
                                            mDistanceUnit.setText(R.string.activity_target_run_mile);
                                            distance = df.format(Double.parseDouble(distance) * 0.62);
                                        mDistance.setText(distance);
                                        mDistance2.setText(distance);
                                        //计算卡路里
                                        float weightF = Float.valueOf(weight);
                                        double alories = weightF * distanceAll * 1.036;
                                        String aloriesStr = String.format(Locale.ENGLISH, "%.2f", alories);
                                        mCalories.setText(aloriesStr);
                                        //通过气压计算海拔
                                        float p0 = SensorManager.PRESSURE_STANDARD_ATMOSPHERE;//海平面标准气压
                                        float p = 1014.22f;//假设当前实时气压
                                        float coef = 1.0f / 5.255f;//系数
                                        float h = 44330.0f * (1.0f - (float) Math.pow(p / p0, coef));//海拔
                                        //通过气压sensor API 调用(需要设备有气压传感器)
                                        //float altitude = mSensorManager.getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, pa);//pa=实时气压
                                        //通过海拔计算气压
                                        float pa = (float) (p0 * (Math.pow(1.0f - 70.0f / 44330.0f, 5.255f)));
                                        //计算速度, 配速
                                        float newRunTime = UnitConvertUtil.runTime(mRunTime.getText().toString());
                                        float duration = newRunTime - oldRunTime;
                                        //计算速度
                                        float speed = 0;
                                        if (duration > 0) {
                                            speed = lineDistance / duration * 60 * 60 / 1000;
                                            //由于GPS数据误差导致短时间内计算出的速度不合常理, 加判断
                                            if (speed >= 20) {// 速度20公里/小时以上为异常数据置0 (人类极限大约为36公里/小时)
                                                speed = 0;
                                        String speedStr = String.format(Locale.ENGLISH, "%.2f", speed);
                                        //计算配速
                                        float pace = 0;
                                        if (speed > 0) {
                                            float sm = speed * 1000 / 60 / 60;//每秒多少米
                                            pace = 1000f / sm;//每公里多少秒
                                            float m = pace / 60;
                                            float s = pace % 60;
                                            if (m >= 0 && s >= 0) {
                                                mPace.setText((int) m + "'" + (int) s + "\"");
                                        String paceStr = String.format(Locale.ENGLISH, "%.2f", pace);
                                        //计算步数
                                        float stride = UnitConvertUtil.stride();//步幅
                                        float step = lineDistance / stride;
                                        String stepStr = String.format(Locale.ENGLISH, "%.0f", step);
                                        allStep += step;
                                        String allStepStr = String.format(Locale.ENGLISH, "%.0f", allStep);
                                        mStepNum.setText(allStepStr);
                                        //计算步频
                                        float stepFreq = 0f;
                                        if (step > 0 && duration > 0) {
                                            stepFreq = step / duration * 60;
                                            if (stepFreq <= 0) {
                                                stepFreq = 0;
                                        String stepFreqStr = String.format(Locale.ENGLISH, "%.0f", stepFreq);
                                        ////////////////计算end///////////////
                                        oldRunTime = newRunTime;
                                        oldLatLng = newLatLng;
                                        SQLiteUtil sqLiteUtil = new SQLiteUtil(getApplicationContext());
                                        SportsMoveDataEn smdEn = new SportsMoveDataEn();
                                        smdEn.user = userId.equals("") ? "000000" : userId;
                                        smdEn.deviceId = dviceMac.equals("1") ? "000000" : dviceMac;
                                        smdEn.sportMode = sportMode;
                                        smdEn.startTime = startTime;
                                        smdEn.sportsTime = String.valueOf(SystemClock.elapsedRealtime() - mRunTime.getBase());
                                        smdEn.distance = distanceStr;
                                        smdEn.calories = aloriesStr;
                                        smdEn.stepNum = stepStr;
                                        smdEn.stepFreq = stepFreqStr;
                                        smdEn.heartRate = "0";//暂无
                                        smdEn.speed = speedStr;
                                        smdEn.pace = paceStr;
                                        smdEn.pa = String.valueOf(pa);
                                        smdEn.altitude = String.valueOf((int)(altitude));
                                        smdEn.lat = String.valueOf(newLatLng.latitude);
                                        smdEn.lng = String.valueOf(newLatLng.longitude);
                                        //保存最新记录, 异常情况重新进入, 继续从断点记录
                                        String sportsDatas = sportMode + "," + startTime + "," +
                                                smdEn.sportsTime + "," + distanceStr + "," +
                                                aloriesStr + "," + smdEn.stepNum;
                                        SmuuApplication.getApplication().setSportsDatas(sportsDatas);
                                        sqLiteUtil.saveSportsData(smdEn);
                                    } else {
                                        //偏移超过40米不记录这条GPS数据
                                        mPolylineOptions.color(Color.GRAY);
                                        mPolylineOptions.setDottedLine(true);// 为虚线
                                        mPolylineOptions.add(oldLatLng, newLatLng);
                                        Polyline polyline = gd_aMap.addPolyline(mPolylineOptions);
                                        oldLatLng = newLatLng;
                                } else {
                                    //mPace.setText("- -");
                    index++;
     * 倒计时3秒
    private int millIndex = 3;
    private Animation animation;
    public OnCountDownTimerListener mOnCountDownTimerListener = new OnCountDownTimerListener() {
        @Override
        public void onTick(long millisUntilFinished) {
            long mill = millisUntilFinished / 1000;
            if (animation != null) {
                animation.reset();
            if (millIndex > 0) {
                mTemrTxt.setText(String.valueOf(mill));
                animation = AnimationUtils.loadAnimation(SportsGDActivity.this, R.anim.sets);
                mTemrTxt.startAnimation(animation);
            startVoice(String.valueOf(mill));
            millIndex--;
        @Override
        public void onFinish() {
            WindowManager.LayoutParams attrs = getWindow().getAttributes();
            attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
            getWindow().setAttributes(attrs);
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
            mTemrTxt.clearAnimation();
            mStartLayout.setVisibility(View.GONE);
            mMapLayout.setVisibility(View.VISIBLE);
            startVoice(getString(R.string.activity_sports_sports_start));// 运动开始 go
            if (sportsDatas.equals("")) {
                // 开始计时
                mRunTime.setBase(SystemClock.elapsedRealtime());
                mRunTime2.setBase(mRunTime.getBase());
                int hour = (int) ((SystemClock.elapsedRealtime() - mRunTime.getBase()) / 1000 / 60 / 60);
                mRunTime.setFormat("0" + String.valueOf(hour) + ":%s");
                mRunTime2.setFormat("0" + String.valueOf(hour) + ":%s");
                mRunTime.start();
                mRunTime2.start();
            } else {
                String[] split = sportsDatas.split(",");
                LogUtils.e("gy", "time: " + split[2]);
                mRunTime.setBase(SystemClock.elapsedRealtime() - Long.parseLong(split[2]));
                mRunTime2.setBase(mRunTime.getBase());
                int hour = (int) ((SystemClock.elapsedRealtime() - mRunTime.getBase()) / 1000 / 60 / 60);
                mRunTime.setFormat("0" + String.valueOf(hour) + ":%s");
                mRunTime2.setFormat("0" + String.valueOf(hour) + ":%s");
                mRunTime.start();
                mRunTime2.start();
//            if (SmuuApplication.getApplication().getCurrConnectState()) {// 连接了手表
//                // 发送 开始GPS运动指令给手表, 经纬度使用APP的, 其他数据使用手表的(扩展预留项)
//            } else {
//                //设置定位回调监听
//                mLocationClient.setLocationListener(mLocationListener);
//            }
            //设置定位回调监听
            mLocationClient.setLocationListener(mLocationListener);
        @Override
        public void onCancel() {
     * 实例化自带语音对象
    private void initTTS() {
        mTextToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if (status == mTextToSpeech.SUCCESS) {
                    mTextToSpeech.setPitch(1.2f);//设置音调,值越大声音越尖(女生),值越小则变成男声,1.0是常规
                    mTextToSpeech.setSpeechRate(1.5f);//用来控制语速
                    //支持下面两种语言
                    if (!SystemUtil.getSystemLanguage().contains("zh")) {
                        mTextToSpeech.setLanguage(Locale.ENGLISH);
                    } else {
                        mTextToSpeech.setLanguage(Locale.CHINESE);
                    startVoice("3");
                } else {
                    LogUtils.e("gye", "Device does not support or data is lost 设备不支持或数据丢失");
                    //showToast("数据丢失或不支持");
     * @param voice
    private void startVoice(String voice) {
        if (isOpenVoice) {
            // 输入文字,若不支持的设备则不会读出来
            mTextToSpeech.speak(voice, TextToSpeech.QUEUE_FLUSH, null, null);
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            showToast(R.string.activity_sports_click_puase_a_sports_over);
            return true;
        return super.onKeyDown(keyCode, event);
}

activity_sports_gd.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.SportsGDActivity">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:id="@+id/mapLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:visibility="visible">
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:orientation="vertical">
                    <!--<com.amap.api.maps2d.MapView-->
                    <com.amap.api.maps.MapView
                        android:id="@+id/gd_map"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:layout_weight="1" />
                    <LinearLayout
                        android:id="@+id/maxInfo"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:paddingBottom="40dp"
                        android:background="@color/white"
                        android:orientation="vertical">
                        <RelativeLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content">
                            <ImageButton
                                android:id="@+id/maxDrawer"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_centerInParent="true"
                                android:background="@drawable/ic_max_drawer" />
                        </RelativeLayout>
                        <RelativeLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:padding="10dp">
                            <TextView
                                android:id="@+id/distance"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_centerInParent="true"
                                android:gravity="center"
                                android:text="0.00"
                                android:textColor="@color/black"
                                android:textSize="36sp" />
                            <TextView
                                android:id="@+id/distanceUnit"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_centerVertical="true"
                                android:layout_marginStart="5dp"
                                android:layout_toEndOf="@+id/distance"
                                android:gravity="center"
                                android:text="@string/activity_target_run_km"
                                android:textColor="@color/black"
                                android:textSize="16sp" />
                        </RelativeLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:padding="5dp">
                            <LinearLayout
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:gravity="center"
                                android:orientation="vertical">
                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/activity_sports_sports_time"
                                    android:textColor="@color/gray" />
                                <Chronometer
                                    android:id="@+id/runTime"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:format="00:00:00"
                                    android:text="00:00:00"
                                    android:textColor="@color/black"
                                    android:textSize="20dp" />
                            </LinearLayout>
                            <LinearLayout
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:gravity="center"
                                android:orientation="vertical">
                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/activity_target_run_kcal"
                                    android:textColor="@color/gray" />
                                <TextView
                                    android:id="@+id/calories"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="0"
                                    android:textColor="@color/black"
                                    android:textSize="20dp" />
                            </LinearLayout>
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:padding="5dp">
                            <LinearLayout
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:gravity="center"
                                android:orientation="vertical">
                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/activity_sports_pace"
                                    android:textColor="@color/gray" />
                                <TextView
                                    android:id="@+id/pace"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="- -"
                                    android:textColor="@color/black"
                                    android:textSize="20dp" />
                            </LinearLayout>
                            <LinearLayout
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:gravity="center"
                                android:orientation="vertical">
                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/fragment_steps_num"
                                    android:textColor="@color/gray" />
                                <TextView
                                    android:id="@+id/step_num"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="- -"
                                    android:textColor="@color/black"
                                    android:textSize="20dp" />
                            </LinearLayout>
                        </LinearLayout>
                        <!--<View
                            android:layout_width="match_parent"
                            android:layout_height="2dp"
                            android:layout_margin="10dp"
                            android:background="?android:attr/listDivider" />-->
                        <RelativeLayout
                            android:layout_width="match_parent"
                            android:layout_height="90dp"
                            android:layout_marginTop="20dp">
                            <RelativeLayout
                                android:id="@+id/lock_true_btn_layout"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_centerInParent="true"
                                android:visibility="gone">
                                <com.yangsion.test.view.CircleBarView
                                    android:id="@+id/progressBarLock"
                                    android:layout_width="70dp"
                                    android:layout_height="70dp"
                                    android:layout_centerInParent="true"
                                    android:visibility="invisible"
                                    app:bar_width="8dp"
                                    app:bg_color="@color/white"
                                    app:progress_color="@color/gray"
                                    app:start_angle="-100"
                                    app:sweep_angle="360" />
                                <ImageButton
                                    android:id="@+id/lock_true"
                                    android:layout_width="55dp"
                                    android:layout_height="55dp"
                                    android:layout_centerInParent="true"
                                    android:background="@drawable/bg_health_item_main_indicator_view2"
                                    android:src="@drawable/ic_lock" />
                            </RelativeLayout>
                            <LinearLayout
                                android:id="@+id/all_btn_layout"
                                android:layout_width="match_parent"
                                android:layout_height="90dp"
                                android:layout_centerInParent="true"
                                android:layout_weight="1"
                                android:gravity="center_vertical"
                                android:orientation="horizontal"
                                android:paddingStart="20dp"
                                android:paddingEnd="20dp"
                                android:visibility="visible">
                                <RelativeLayout
                                    android:id="@+id/lock_btn_layout"
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"
                                    android:layout_weight="1">
                                    <ImageButton
                                        android:id="@+id/lock"
                                        android:layout_width="wrap_content"
                                        android:layout_height="wrap_content"
                                        android:layout_centerInParent="true"
                                        android:background="@drawable/ic_lock" />
                                </RelativeLayout>
                                <RelativeLayout
                                    android:id="@+id/stop_btn_Layout"
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"
                                    android:layout_weight="1"
                                    android:visibility="gone">
                                    <com.yangsion.test.view.CircleBarView
                                        android:id="@+id/progressBarStop"
                                        android:layout_width="70dp"
                                        android:layout_height="70dp"
                                        android:layout_centerInParent="true"
                                        android:visibility="invisible"
                                        app:bar_width="8dp"
                                        app:bg_color="@color/white"
                                        app:progress_color="@color/gray"
                                        app:start_angle="-100"
                                        app:sweep_angle="360" />
                                    <ImageButton
                                        android:id="@+id/stop"
                                        android:layout_width="60dp"
                                        android:layout_height="60dp"
                                        android:layout_centerInParent="true"
                                        android:background="@drawable/ic_stop" />
                                </RelativeLayout>
                                <RelativeLayout
                                    android:id="@+id/pause_btn_Layout"
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"
                                    android:layout_weight="1"
                                    android:visibility="visible">
                                    <ImageButton
                                        android:id="@+id/pause"
                                        android:layout_width="60dp"
                                        android:layout_height="60dp"
                                        android:layout_centerInParent="true"
                                        android:background="@drawable/ic_pause" />
                                </RelativeLayout>
                                <RelativeLayout
                                    android:id="@+id/start_btn_Layout"
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"
                                    android:layout_weight="1"
                                    android:visibility="gone">
                                    <ImageButton
                                        android:id="@+id/start"
                                        android:layout_width="60dp"
                                        android:layout_height="60dp"
                                        android:layout_centerInParent="true"
                                        android:background="@drawable/ic_start2" />
                                </RelativeLayout>
                                <RelativeLayout
                                    android:id="@+id/voice_btn_layout"
                                    android:layout_width="match_parent"
                                    android:layout_height="match_parent"
                                    android:layout_weight="1">
                                    <ImageButton
                                        android:id="@+id/voice"
                                        android:layout_width="wrap_content"
                                        android:layout_height="wrap_content"
                                        android:layout_centerInParent="true"
                                        android:background="@drawable/ic_voice" />
                                </RelativeLayout>
                            </LinearLayout>
                        </RelativeLayout>
                    </LinearLayout>
                    <LinearLayout
                        android:id="@+id/mixInfo"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:paddingBottom="40dp"
                        android:background="@color/white"
                        android:orientation="vertical"
                        android:visibility="gone">
                        <RelativeLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content">
                            <ImageButton
                                android:id="@+id/mixDrawer"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_centerInParent="true"
                                android:background="@drawable/ic_mix_drawer" />
                        </RelativeLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:gravity="center"
                            android:orientation="horizontal">
                            <RelativeLayout
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_weight="1">
                                <TextView
                                    android:id="@+id/distance2"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:layout_centerInParent="true"
                                    android:gravity="center"
                                    android:text="0.00"
                                    android:textColor="@color/black"
                                    android:textSize="36sp" />
                                <TextView
                                    android:id="@+id/runNumUnit2"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:layout_centerVertical="true"
                                    android:layout_marginStart="5dp"
                                    android:layout_toEndOf="@+id/distance2"
                                    android:gravity="center"
                                    android:text="@string/activity_target_run_km"
                                    android:textColor="@color/black"
                                    android:textSize="16sp" />
                            </RelativeLayout>
                            <LinearLayout
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:gravity="center"
                                android:orientation="vertical">
                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/activity_sports_sports_time"
                                    android:textColor="@color/gray" />
                                <Chronometer
                                    android:id="@+id/runTime2"
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:format="00:00:00"
                                    android:text="00:00:00"
                                    android:textColor="@color/black"
                                    android:textSize="20dp" />
                            </LinearLayout>
                        </LinearLayout>
                    </LinearLayout>
                </LinearLayout>
                <RelativeLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="20dp"
                    android:layout_marginTop="40dp">
                    <androidx.cardview.widget.CardView
                        android:id="@+id/card_gps"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        app:cardBackgroundColor="@color/white"
                        app:cardCornerRadius="6dp"
                        android:layout_centerVertical="true"
                        app:cardElevation="2dp"
                        app:contentPadding="3dp">
                        <LinearLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:gravity="center"
                            android:orientation="horizontal">
                            <TextView
                                android:id="@+id/gps_desc"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_alignParentBottom="true"
                                android:text="GPS"
                                android:textColor="@color/black"
                                android:textSize="10sp" />
                            <RelativeLayout
                                android:layout_width="wrap_content"
                                android:layout_height="10dp"
                                android:layout_gravity="center_vertical"
                                android:layout_marginStart="5dp">
                                <ImageView
                                    android:id="@+id/gps_signal0"
                                    android:layout_width="2dp"
                                    android:layout_height="4dp"
                                    android:layout_alignParentBottom="true"
                                    android:background="@color/gray" />
                                <ImageView
                                    android:id="@+id/gps_signal1"
                                    android:layout_width="2dp"
                                    android:layout_height="6dp"
                                    android:layout_alignParentBottom="true"
                                    android:layout_marginStart="2dp"
                                    android:layout_toEndOf="@+id/gps_signal0"
                                    android:background="@color/gray" />
                                <ImageView
                                    android:id="@+id/gps_signal2"
                                    android:layout_width="2dp"
                                    android:layout_height="8dp"
                                    android:layout_alignParentBottom="true"
                                    android:layout_marginStart="2dp"
                                    android:layout_toEndOf="@+id/gps_signal1"
                                    android:background="@color/gray" />
                                <ImageView
                                    android:id="@+id/gps_signal3"
                                    android:layout_width="2dp"
                                    android:layout_height="10dp"
                                    android:layout_alignParentBottom="true"
                                    android:layout_marginStart="2dp"
                                    android:layout_toEndOf="@+id/gps_signal2"
                                    android:background="@color/gray" />
                            </RelativeLayout>
                        </LinearLayout>
                    </androidx.cardview.widget.CardView>
                    <TextView
                        android:id="@+id/gps_status_desc"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_toEndOf="@+id/card_gps"
                        android:padding="5dp"
                        android:layout_centerVertical="true"
                        android:layout_marginStart="20dp"
                        android:textColor="@color/white"
                        android:visibility="gone"
                        android:textSize="10sp"
                        android:background="@drawable/bg_gps_status_desc"
                        android:text=""/>
                </RelativeLayout>
                <com.google.android.material.floatingactionbutton.FloatingActionButton
                    android:id="@+id/history"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentEnd="true"
                    android:layout_marginTop="30dp"
                    android:layout_marginEnd="20dp"
                    android:clickable="true"
                    android:padding="5dp"
                    android:scaleType="center"
                    android:visibility="gone"
                    app:backgroundTint="@color/white"
                    app:elevation="6dp"
                    app:fabCustomSize="36dp"
                    app:rippleColor="@color/gray"
                    app:srcCompat="@drawable/ic_history" />
            </RelativeLayout>
        </LinearLayout>
        <RelativeLayout
            android:id="@+id/startLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/orangereds"
            android:visibility="visible">
            <TextView
                android:id="@+id/temrTxt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:gravity="center"
                android:text=""
                android:textColor="@color/white"
                android:textSize="100sp" />
        </RelativeLayout>
    </RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

CircleBarView.java

package com.yangsion.test.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.TextView;
import android.widget.Toast;
import com.yangsion.test.R;
public class CircleBarView extends View {
    private Paint bgPaint;//绘制背景圆弧的画笔
    private Paint progressPaint;//绘制圆弧的画笔
    private RectF mRectF;//绘制圆弧的矩形区域
    private CircleBarAnim anim;
    private float progressNum;//可以更新的进度条数值
    private float maxNum;//进度条最大值
    private int progressColor;//进度条圆弧颜色
    private int bgColor;//背景圆弧颜色
    private float startAngle;//背景圆弧的起始角度
    private float sweepAngle;//背景圆弧扫过的角度
    private float barWidth;//圆弧进度条宽度
    private int defaultSize;//自定义View默认的宽高
    private float progressSweepAngle;//进度条圆弧扫过的角度
    private TextView textView;
    private OnAnimationListener onAnimationListener;
    private Context context;
    public CircleBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init(context,attrs);
    private void init(Context context,AttributeSet attrs){
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleBarView);
        progressColor = typedArray.getColor(R.styleable.CircleBarView_progress_color, getResources().getColor(R.color.orangereds,null));
        bgColor = typedArray.getColor(R.styleable.CircleBarView_bg_color,getResources().getColor(R.color.white,null));
        startAngle = typedArray.getFloat(R.styleable.CircleBarView_start_angle,0);
        sweepAngle = typedArray.getFloat(R.styleable.CircleBarView_sweep_angle,360);
        barWidth = typedArray.getDimension(R.styleable.CircleBarView_bar_width,UIUtils.dp2px(context,10));
        typedArray.recycle();
        progressNum = 0;
        maxNum = 100;
        defaultSize = UIUtils.dp2px(context,150);
        mRectF = new RectF();
        progressPaint = new Paint();
        progressPaint.setStyle(Paint.Style.STROKE);//只描边,不填充
        progressPaint.setColor(progressColor);
        progressPaint.setAntiAlias(true);//设置抗锯齿
        progressPaint.setStrokeWidth(barWidth);
        progressPaint.setStrokeCap(Paint.Cap.ROUND);//设置画笔为圆角
        bgPaint = new Paint();
        bgPaint.setStyle(Paint.Style.STROKE);//只描边,不填充
        bgPaint.setColor(bgColor);
        bgPaint.setAntiAlias(true);//设置抗锯齿
        bgPaint.setStrokeWidth(barWidth);
        bgPaint.setStrokeCap(Paint.Cap.ROUND);
        anim = new CircleBarAnim();
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int height = measureSize(defaultSize, heightMeasureSpec);
        int width = measureSize(defaultSize, widthMeasureSpec);
        int min = Math.min(width, height);// 获取View最短边的长度
        setMeasuredDimension(min, min);// 强制改View为以最短边为长度的正方形
        if(min >= barWidth*2){
            mRectF.set(barWidth/2,barWidth/2,min-barWidth/2,min-barWidth/2);
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawArc(mRectF,startAngle,sweepAngle,false,bgPaint);
        canvas.drawArc(mRectF,startAngle,progressSweepAngle,false, progressPaint);
    public class CircleBarAnim extends Animation {
        public CircleBarAnim(){
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {//interpolatedTime从0渐变成1,到1时结束动画,持续时间由setDuration(time)方法设置
            super.applyTransformation(interpolatedTime, t);
            progressSweepAngle = interpolatedTime * sweepAngle * progressNum / maxNum;
            if(onAnimationListener!=null){
                if(textView !=null){
                    textView.setText(onAnimationListener.howToChangeText(interpolatedTime, progressNum,maxNum));
                onAnimationListener.howTiChangeProgressColor(progressPaint,interpolatedTime, progressNum,maxNum);
            postInvalidate();
    public interface OnAnimationEndListener {
        void onAnimationEnd();
    public OnAnimationEndListener onAnimationEndListener;
    public void setOnAnimationEndListener(OnAnimationEndListener onAnimationEndListener){
        this.onAnimationEndListener = onAnimationEndListener;
    private int measureSize(int defaultSize,int measureSpec) {
        int result = defaultSize;
        int specMode = View.MeasureSpec.getMode(measureSpec);
        int specSize = View.MeasureSpec.getSize(measureSpec);
        if (specMode == View.MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == View.MeasureSpec.AT_MOST) {
            result = Math.min(result, specSize);
        return result;
     * 设置进度条最大值
     * @param maxNum
    public void setMaxNum(float maxNum) {
        this.maxNum = maxNum;
     * 设置进度条数值
     * @param progressNum 进度条数值
     * @param time 动画持续时间
    public void setProgressNum(float progressNum, int time) {
        this.progressNum = progressNum;
        if (time > 0) {
            anim.setDuration(time);
            this.startAnimation(anim);
     * 获取进度条数值
    public float getProgressNum() {
        return this.progressNum;
    @Override
    protected void onAnimationEnd() {
        super.onAnimationEnd();
        onAnimationEndListener.onAnimationEnd();
     * 设置显示文字的TextView
     * @param textView
    public void setTextView(TextView textView) {
        this.textView = textView;
    public interface OnAnimationListener {
         * 如何处理要显示的文字内容
         * @param interpolatedTime 从0渐变成1,到1时结束动画
         * @param updateNum 进度条数值
         * @param maxNum 进度条最大值
         * @return
        String howToChangeText(float interpolatedTime, float updateNum, float maxNum);
         * 如何处理进度条的颜色
         * @param paint 进度条画笔
         * @param interpolatedTime 从0渐变成1,到1时结束动画
         * @param updateNum 进度条数值
         * @param maxNum 进度条最大值
        void howTiChangeProgressColor(Paint paint, float interpolatedTime, float updateNum, float maxNum);
    public void setOnAnimationListener(OnAnimationListener onAnimationListener) {
        this.onAnimationListener = onAnimationListener;

attrs.xml

<!--注意这里的name要和自定义View的名称一致,不然在xml布局中无法引用-->
    <declare-styleable name="CircleBarView">
        <attr name="progress_color" format="color"></attr>
        <attr name="bg_color" format="color"></attr>
        <attr name="bar_width" format="dimension"></attr>
        <attr name="start_angle" format="float"></attr>
        <attr name="sweep_angle" format="float"></attr>
    </declare-styleable>

2)绘制数据库获取的GPS数据

为下图代码

TrajectoryFragment.java

package com.yangsion.test.fragment.sports.record;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdate;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.CoordinateConverter;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.CameraPosition;
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.MyLocationStyle;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.maps.utils.SpatialRelationUtil;
import com.amap.api.maps.utils.overlay.MovingPointOverlay;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.yangsion.test.R;
import com.yangsion.test.activity.BaseActivity;
import com.yangsion.test.activity.SharePreviewActivity;
import com.yangsion.test.application.SmuuApplication;
import com.yangsion.test.db.SQLiteUtil;
import com.yangsion.test.en.SportsMoveDataEn;
import com.yangsion.test.en.SportsNumDataEn;
import com.yangsion.test.util.UnitConvertUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class TrajectoryFragment extends Fragment implements View.OnClickListener {
    private MapView mGdMap;
    private RelativeLayout mDataView;
    private TextView mDistance;
    private TextView mDistanceUnit;
    private TextView mStartTime;
    private TextView mSportsTime;
    private TextView mAveragePace;
    private TextView mCalories;
    private FloatingActionButton mHiedView;
    private FloatingActionButton mSendView;
    private MyLocationStyle myLocationStyle;
    private AMap gd_aMap = null;
    //声明AMapLocationClient类对象
    public AMapLocationClient mLocationClient = null;
    //声明AMapLocationClientOption对象
    public AMapLocationClientOption mLocationOption = null;
    public CameraUpdate cameraUpdate = null;
    private SportsNumDataEn sportsNumDataEn = null;
    private List<LatLng> latlngList = new ArrayList<>();
    //是否显示地图内容
    private boolean isHiedView = false;
    public static TrajectoryFragment newInstance(Bundle sndEn_bundle) {
        TrajectoryFragment fragment = new TrajectoryFragment();
        fragment.setArguments(sndEn_bundle);
        return fragment;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            sportsNumDataEn = (SportsNumDataEn) getArguments().getSerializable("sndEn");
    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_trajectory, container, false);
        initView(root, savedInstanceState);
        initData();
        return root;
    @Override
    public void onResume() {
        super.onResume();
        mGdMap.onResume();
    @Override
    public void onPause() {
        super.onPause();
        mGdMap.onPause();
    @Override
    public void onDestroy() {
        super.onDestroy();
        mGdMap.onDestroy();
    private void initView(View root, Bundle savedInstanceState) {
        mGdMap = (MapView) root.findViewById(R.id.gd_map);
        mDataView = (RelativeLayout) root.findViewById(R.id.dataView);
        mGdMap.onCreate(savedInstanceState);
        mDistance = (TextView) root.findViewById(R.id.distance);
        mDistanceUnit = (TextView) root.findViewById(R.id.distanceUnit);
        mStartTime = (TextView) root.findViewById(R.id.startTime);
        mSportsTime = (TextView) root.findViewById(R.id.sportsTime);
        mAveragePace = (TextView) root.findViewById(R.id.averagePace);
        mCalories = (TextView) root.findViewById(R.id.calories);
        mHiedView = (FloatingActionButton) root.findViewById(R.id.hiedView);
        mHiedView.setOnClickListener(this::onClick);
        mSendView = (FloatingActionButton) root.findViewById(R.id.sendView);
        mSendView.setOnClickListener(this::onClick);
    private void initData() {
        UnitConvertUtil.drinkType(sportsNumDataEn.distance, mDistance, mDistanceUnit);
        mStartTime.setText(sportsNumDataEn.startTime);
        if (sportsNumDataEn.deviceType.equals("0")) {//0手机,1手表
            mSportsTime.setText(UnitConvertUtil.getGapTime(Long.parseLong(sportsNumDataEn.sportsTime)));
        } else {
            mSportsTime.setText(UnitConvertUtil.getGapTime2(Long.parseLong(sportsNumDataEn.sportsTime)));
        mCalories.setText(sportsNumDataEn.calories);
        if (gd_aMap == null) {
            gd_aMap = mGdMap.getMap();
        SQLiteUtil sqLiteUtil = new SQLiteUtil(getActivity().getApplicationContext());
        List<SportsMoveDataEn> allSportsData = sqLiteUtil.getAllSportsData();
//        LogUtils.d("gy", "allSportsData.size :" + allSportsData.size());
        if (allSportsData.size() > 0) {
            float allPace = 0;
            for (SportsMoveDataEn en : allSportsData) {
//                LogUtils.e("gy", "sportsNumDataEn.startTime :" + sportsNumDataEn.startTime);
//                LogUtils.e("gy", "en.startTime :" + en.startTime);
                if (sportsNumDataEn.startTime.equals(en.startTime)) {
//                    LogUtils.d("gy", "startTime :" + en.startTime);
//                    LogUtils.d("gy", "distance :" + en.distance);
//                    LogUtils.d("gy", "calories :" + en.calories);
//                    LogUtils.d("gy", "pace :" + en.pace);
//                    LogUtils.d("gy", "lat :" + en.lat);
//                    LogUtils.d("gy", "lng :" + en.lng);
                    allPace += Float.parseFloat(en.pace);
                    LatLng latLng = new LatLng(Double.parseDouble(en.lat), Double.parseDouble(en.lng));
                    if (sportsNumDataEn.deviceType.equals("1")) {
                        CoordinateConverter converter = new CoordinateConverter(getActivity());
                        // CoordType.GPS 待转换坐标类型
                        converter.from(CoordinateConverter.CoordType.GPS);
                        // sourceLatLng待转换坐标点 LatLng类型
                        converter.coord(latLng);
                        // 执行转换操作
                        latLng = converter.convert();
//                        LogUtils.d("gy", "latitude:" + latLng.latitude);
//                        LogUtils.d("gy", "longitude:" + latLng.longitude);
                    latlngList.add(latLng);
            if (sportsNumDataEn.deviceType.equals("0")) {
                UnitConvertUtil.averagePace(allPace / allSportsData.size(), mAveragePace, null);
            } else {
                mAveragePace.setText(sportsNumDataEn.pace);
            gd_aMap.clear();
            gd_aMap.setMapType(AMap.MAP_TYPE_NORMAL);
            gd_aMap.getUiSettings().setZoomControlsEnabled(false);//去掉地图右下角隐藏的缩放按钮
            if (latlngList.size() > 0) {
                LatLng replayGeoPoint = latlngList.get(0);
                cameraUpdate = CameraUpdateFactory.newCameraPosition(new CameraPosition(replayGeoPoint, 15, 10, 10));
                gd_aMap.moveCamera(cameraUpdate);
                mHandler.sendEmptyMessageDelayed(200, 1000);
    @Override
    public void onClick(View v) {
        if (v == mHiedView) {
            if (isHiedView) {
                //gd_aMap.setTrafficEnabled(true);
                gd_aMap.showBuildings(true);
                gd_aMap.showMapText(true);
                //gd_aMap.setConstructingRoadEnable(true);
                gd_aMap.setMapType(AMap.MAP_TYPE_NORMAL);
                isHiedView = false;
            } else {
                hiedView();
                isHiedView = true;
        } else if (v == mSendView) {// 分享预览
            int measuredWidth = mDataView.getMeasuredWidth();
            int measuredHeight = mDataView.getMeasuredHeight();
            Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            mDataView.draw(canvas);
            SmuuApplication.getApplication().bitmaps[1] = bitmap;
            // 获取高德地图Bitmap
            gd_aMap.getMapScreenShot(new AMap.OnMapScreenShotListener() {
                @Override
                public void onMapScreenShot(Bitmap bitmap) {
                @Override
                public void onMapScreenShot(Bitmap bitmap, int status) {
                    if (null != bitmap) {
                        SmuuApplication.getApplication().bitmaps[0] = bitmap;
                        BaseActivity.startActivity(getActivity(), SharePreviewActivity.class, Intent.FLAG_ACTIVITY_SINGLE_TOP, false);
     * 不显示地图内容
    private void hiedView() {
        gd_aMap.setTrafficEnabled(false);
        gd_aMap.showBuildings(false);
        gd_aMap.showMapText(false);
        gd_aMap.setConstructingRoadEnable(false);
        String style = copyFile("gd_map_style/style.data", "/GD_MAP_STYLE", "style.data");
        String style_extra = copyFile("gd_map_style/style_extra.data", "/GD_MAP_STYLE", "style_extra.data");
        gd_aMap.setCustomMapStyle(
                new com.amap.api.maps.model.CustomMapStyleOptions()
                        .setEnable(true)
                        .setStyleDataPath(style)
                        .setStyleExtraPath(style_extra)
//                .setStyleTexturePath("/mnt/sdcard/amap/textures.zip")
                        .setStyleTexturePath(null)
    private String copyFile(String path, String parent, String name) {
        // "GD_MAP_STYLE" "GOOGLE_MAP_STYLE"
        String path_sd = getActivity().getExternalFilesDir(null).getPath() + parent;
        try {
            File file_folder = new File(path_sd);
            if (!file_folder.exists()) {
                file_folder.mkdirs();
            File file = new File(path_sd, name);
            InputStream inputStream = getActivity().getAssets().open(path);
            int index;
            byte[] bytes = new byte[1024];
            FileOutputStream loadFile = new FileOutputStream(file);
            while ((index = inputStream.read(bytes)) != -1) {
                loadFile.write(bytes, 0, index);
                loadFile.flush();
            inputStream.close();
            loadFile.close();
            return file.getAbsolutePath();
        } catch (Exception exception) {
            exception.printStackTrace();
        return null;
    private void drawLine() {
        LatLng replayGeoPoint = latlngList.get(0);
        LatLng replayEndPoint = latlngList.get(latlngList.size() - 1);
        LatLngBounds bounds = new LatLngBounds(latlngList.get(0), latlngList.get(latlngList.size() - 2));
        gd_aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
        /*已过时
        //SmoothMoveMarker smoothMarker = new SmoothMoveMarker(gd_aMap);
        //// 设置滑动的图标
        //smoothMarker.setDescriptor(BitmapDescriptorFactory.fromResource(R.drawable.danwiqiehuan));
        // 添加位置
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions
                //.position(replayGeoPoint)
                .title("移动icon")
                .snippet("")
                .icon(BitmapDescriptorFactory
                        .fromBitmap(BitmapFactory.decodeResource(
                                getResources(), R.drawable.ic_line_head)))
                .anchor(0.5f, 0.5f);
        Marker marker = gd_aMap.addMarker(markerOptions);
        MovingPointOverlay smoothMarker = new MovingPointOverlay(gd_aMap, marker);
        LatLng drivePoint = latlngList.get(0);
        Pair<Integer, LatLng> pair = SpatialRelationUtil.calShortestDistancePoint(latlngList, drivePoint);
        latlngList.set(pair.first, drivePoint);
        List<LatLng> subList = latlngList.subList(pair.first, latlngList.size());
        // 设置滑动的轨迹左边点
        smoothMarker.setPoints(subList);
        // 设置滑动的总时间
        if (latlngList.size() < 20) {
            smoothMarker.setTotalDuration(1);
        } else if (latlngList.size() < 50) {
            smoothMarker.setTotalDuration(2);
        } else {
            smoothMarker.setTotalDuration(5);
        // 开始滑动
        smoothMarker.startSmoothMove();
        // 移动监听
        LatLng[] oldLatlng = {latlngList.get(0)};
        smoothMarker.setMoveListener(new MovingPointOverlay.MoveListener() {
            @Override
            public void move(double v) {
//                LogUtils.i("gy", "move: " + v);
                if (v == 0) {
                    //hiedView();
                    marker.remove();
                    gd_aMap.addMarker(new MarkerOptions()
                            .position(replayEndPoint)
                            .title("终点")
                            .icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
                                    .decodeResource(
                                            getResources(),
                                            R.drawable.ic_stop_point))));
                cameraUpdate = CameraUpdateFactory.newCameraPosition(new CameraPosition(smoothMarker.getPosition(), 18, 10, 10));
                gd_aMap.setMapType(AMap.MAP_TYPE_NORMAL);
                gd_aMap.animateCamera(cameraUpdate);
                // 绘制移动线
                if (oldLatlng[0].latitude != smoothMarker.getPosition().latitude &&
                        oldLatlng[0].longitude != smoothMarker.getPosition().longitude) {
                    PolylineOptions polylineOptions = new PolylineOptions()
                            .add(oldLatlng[0], smoothMarker.getPosition())
                            .color(Color.GREEN).width(10f);
                    gd_aMap.addPolyline(polylineOptions);
                    oldLatlng[0] = smoothMarker.getPosition();
                // 经纬度转屏幕像素
//                Point point = gd_aMap.getProjection().toScreenLocation(smoothMarker.getPosition());
//                LogUtils.d("gy_view", "point.x: " + point.x);
//                LogUtils.d("gy_view", "point.y: " + point.y);
        gd_aMap.addMarker(new MarkerOptions()
                .position(replayGeoPoint)
                .title("起点")
                .icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
                        .decodeResource(
                                getResources(),
                                R.drawable.ic_starting_point))));
//        gd_aMap.addMarker(new MarkerOptions()
//                .position(replayEndPoint)
//                .title("终点")
//                .icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
//                        .decodeResource(
//                                getResources(),
//                                R.drawable.ic_stop_point))));
    public Handler mHandler = new Handler(new WeakReference<Handler.Callback>(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            if (msg.what == 200) {
                if (isAdded()) {
                    drawLine();
                return true;