如何在安卓系统中制作gpx文件

问题描述 投票:0回答:1

我想用DOM和Transformer编写gpx文件。

我的代码是这样的

try {
    val document =
      DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
    val trkpt = document.createElement("trkpt")
    trkpt.setAttribute("lat", "-33.626932")
    trkpt.setAttribute("lon", "-33.626932")
    val ele = document.createElement("ele")
    ele.appendChild(document.createTextNode("-6"))
    trkpt.appendChild(ele)
    document.appendChild(trkpt)
    val transformer = TransformerFactory.newInstance().newTransformer()
    transformer.setOutputProperty(OutputKeys.METHOD,"gpx")

    val saveFolder = File(folderPath) // 저장 경로
    if (!saveFolder.exists()) {       //폴더 없으면 생성
      saveFolder.mkdir()
    }
    val path = "route_${System.currentTimeMillis()}.gpx"
    val file = File(saveFolder, path)         //로컬에 파일저장

    val source = DOMSource(document)
    //val result = StreamResult(FileOutputStream(file))
    val result = StreamResult(System.out)
    transformer.transform(source, result)
    return Uri.fromFile(file)
  }catch(e:Exception){
    e.printStackTrace()
  }

产量是这样的

<?xml version="1.0" encoding="UTF-8"?><trkpt lat="-33.626932" lon="-33.626932"><ele>-6</ele></trkpt>

但我想把标签改成 ,像这样的。

<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creator="TraceDeTrail http://www.tracedetrail.fr" version="1.1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd ">

我怎么能像这样编辑,属性以及

我之所以尝试从JPGX改成自己,是因为我需要从航点获取时间。请在这里输入图像描述

有时候,我需要从WayPoint类中获取时间,但时间的类型是ZonedDateTime,但这在SDK 24上是行不通的......有什么办法可以从WayPoint中获取时间吗?


我在Gradle上添加了ThreeTenABP,但我不知道我到底如何使用它,我在Gradle上添加了库,并在app-instance中init,但它仍然会出错。

 wpList.add(
      WayPoint.builder()
        .lat(currentLatLng.latitude)
        .lon(currentLatLng.longitude)
        .name("Start")
        .desc("Start Description")
        .time(System.currentTimeMillis())  <- RunningActivity.kt:107
        .type(START_POINT)
        .build()
    )
2020-05-06 16:46:16.895 8877-8877/com.umpa2020.tracer E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.umpa2020.tracer, PID: 8877
    java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/Instant;
        at io.jenetics.jpx.WayPoint$Builder.time(WayPoint.java:767)
        at com.umpa2020.tracer.main.start.running.RunningActivity.start(RunningActivity.kt:107)
        at com.umpa2020.tracer.main.start.running.RunningActivity.onSingleClick(RunningActivity.kt:175)
        at com.umpa2020.tracer.util.OnSingleClickListener$DefaultImpls.onClick(OnSingleClickListener.kt:19)
        at com.umpa2020.tracer.main.start.BaseRunningActivity.onClick(BaseRunningActivity.kt:45)
        at android.view.View.performClick(View.java:5610)
        at android.view.View$PerformClick.run(View.java:22265)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "java.time.Instant" on path: DexPathList[[zip file "/data/app/com.umpa2020.tracer-2/base.apk"],nativeLibraryDirectories=[/data/app/com.umpa2020.tracer-2/lib/x86, /system/lib, /vendor/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at io.jenetics.jpx.WayPoint$Builder.time(WayPoint.java:767) 
        at com.umpa2020.tracer.main.start.running.RunningActivity.start(RunningActivity.kt:107) 
        at com.umpa2020.tracer.main.start.running.RunningActivity.onSingleClick(RunningActivity.kt:175) 
        at com.umpa2020.tracer.util.OnSingleClickListener$DefaultImpls.onClick(OnSingleClickListener.kt:19) 
        at com.umpa2020.tracer.main.start.BaseRunningActivity.onClick(BaseRunningActivity.kt:45) 
        at android.view.View.performClick(View.java:5610) 
        at android.view.View$PerformClick.run(View.java:22265) 
        at android.os.Handler.handleCallback(Handler.java:751) 
        at android.os.Handler.dispatchMessage(Handler.java:95) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6077) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 
android xml kotlin dom gpx
1个回答
0
投票

gpx本质上是一个特殊的xml。你说的是 XML命名空间.

如何创建呢。创建XML头

一个xml文件只能有一个根元素,但有这么多的 trkpt gpx文件中的元素。所以 trkpt 项目不应该是一个根元素。你应该包括所有的 trkpt 单元 gpx 元素,它是你的gpx文件的根元素。

要在Android中生成一个gpx文件,更好的选择是使用一个库。它们中的大多数都可以帮助你进行上述所有操作。

我现在使用的是 io.jenetics.jpx 在我的android项目中,它工作得很好。

XML不支持追加元素。如果你想在记录时生成一个gpx文件,你应该用一个可追加的形式来做,比如任何一个 Serializable 类型。完成记录后,您可以从序列化文件中创建一个有效的GPX文件。

WayPoint in jpx是一个Serializable类型,我正在使用它。

你也可以用Android的 Location,它实现了 Parcelable,android实现像Serializable。

我的代码.jpx包含了zonedDateTime类,它在java8中工作。

public class TrackService extends Service {
    private int notificationId = 142857 ;
    NotificationCompat.Builder builder;
    NotificationManagerCompat notificationManager;
    private Timer timer = new Timer(true);
    private static final String CHANNEL_ID = "org.kib.qtp";
    private File serializerFile;
    private ObjectOutputStream oos;
    private Long basetime;
    SimpleDateFormat sdf;

    @Override
    public void onCreate(){
        super.onCreate();
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
        builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_map_black_24dp)
                .setContentTitle(getString(R.string.track))
                .setContentText(getString(R.string.tracktext))
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setOngoing(true)
                .setOnlyAlertOnce(true)
                .setContentIntent(pendingIntent);
        notificationManager = NotificationManagerCompat.from(this);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            startForeground (notificationId, builder.build());
        else
            notificationManager.notify(notificationId, builder.build());
    }

    @Override
    public void onDestroy(){
        try {
            endTrack();
        } catch (IOException e) {
            e.printStackTrace();
        }
        stopForeground(true);
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        /**
         * @param ele require altitude or not
         * @param time update time
         * @param fine fine location or not
         * @param name the gpx file's name
         */
        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", getResources(). getConfiguration().locale);

        int time = 60000;
        boolean ele = false;
        boolean fine = false;
        String name = Calendar.getInstance().getTime().toString().replaceAll(" ", "_");

        if (intent.hasExtra("time"))
            Objects.requireNonNull(intent.getExtras()).getInt("time");
        if (intent.hasExtra("ele"))
            Objects.requireNonNull(intent.getExtras()).getBoolean("ele");
        if (intent.hasExtra("fine"))
            Objects.requireNonNull(intent.getExtras()).getBoolean("fine");
        if (intent.hasExtra("name"))
            Objects.requireNonNull(intent.getExtras()).getString("name");

        File path = new File(getFilesDir().getAbsolutePath() + "/gpx");
        while(!path.exists())
            path.mkdirs();
        try {
            serializerFile = new File(getFilesDir().getAbsolutePath() + "/gpx/" + name );
            if (serializerFile.exists())
                serializerFile.delete();
            while(!serializerFile.exists())
                serializerFile.createNewFile();
            oos = new ObjectOutputStream(new FileOutputStream(serializerFile));
        } catch (IOException e) {
            e.printStackTrace();
        }
        basetime = 0L;
        Toast.makeText(this, R.string.toast_start_tracking, Toast.LENGTH_SHORT).show();
        startTrack(time, ele, fine);
        return START_STICKY;
    }

    private void endTrack() throws IOException {
        timer.cancel();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(serializerFile));
        TrackSegment.Builder segment = TrackSegment.builder();
        while (true) {
            try{
                WayPoint wp = (WayPoint) ois.readObject();
                segment.addPoint(wp);
            } catch (EOFException e) {
                break;
            } catch (ClassNotFoundException ignored){

            }
        }
        final GPX gpx = GPX.builder().addTrack(track -> track.addSegment(segment.build())).build();
        GPX.write(gpx, serializerFile.getAbsolutePath() + ".gpx");
        Toast.makeText(this, R.string.toast_gpx_write, Toast.LENGTH_SHORT).show();
        new File(serializerFile.getAbsolutePath() + ".tobeupload").createNewFile();;
    }

    private void startTrack(int time, boolean ele, boolean fine) {

        TimerTask task = new TimerTask() {
            public void run() {
                Location location = getLocation(ele, fine);
                if (location != null){
                    try {
                        if (location.getTime() != basetime){
                            basetime = location.getTime();
                            WayPoint point = WayPoint.builder().lat(location.getLatitude()).lon(location.getLongitude()).ele(location.getAltitude()).time(location.getTime()).build();
                            if (point != null){
                                oos.writeObject(point);
                                NotificationCompat.Builder timerBuilder = builder.setContentText(getString(R.string.tracktext) + sdf.format(location.getTime()));
                                Log.i("track", location.getLatitude() +","+ location.getLongitude() +","+ location.getAltitude());
                                notificationManager.notify(notificationId,timerBuilder.build());
                            }
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        };  
        timer.schedule(task, 0, time);  
    }

    private Location getLocation(boolean ele, boolean fine) {
        //get location here
    }
}

jpx包含了zonedDateTime类,它在java8中工作。但它被它的创建者Stephen Colebourne移植到了Java 6中,并且也作为一个库移植到了早期的android版本中。

库在这里。JakeWhartonThreeTenABP -- 一个适用于Android的JSR -310的回传。

以及如何使用。如何在Android项目中使用ThreeTenABP - StackOverFlow.

© www.soinside.com 2019 - 2024. All rights reserved.