как сделать файл gpx в android - PullRequest
1 голос
/ 01 мая 2020

Я хочу написать файл gpx с DOM и Transformer

Мой код такой

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 ">

Как я могу так отредактировать атрибуты

причина, по которой я пытаюсь перейти от JPX к себе, заключается в том, что мне нужно получить время от путевой точки. введите описание изображения здесь

Иногда мне нужно получить время из класса WayPoint, но тип времени - ZonedDateTime. но это не работает в SDK 24 ... есть ли какое-нибудь решение получить время из путевой точки?


Я добавляю ThreeTenABP, но я не знаю, как именно это использовать. Я добавляю библиотеку в Gradle и init в app-instance, но она все равно выдает ошибку

 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) 

1 Ответ

0 голосов
/ 02 мая 2020

gpx - это, по сути, особый xml. То, о чем вы говорите, это XML Пространство имен .

Как его создать: как создать XML заголовок

A Файл xml может иметь только один элемент root, но в файле gpx столько элементов trkpt. Поэтому элемент trkpt не должен быть элементом root. Вы должны включить все элементы trkpt в один элемент gpx, который является элементом root вашего файла gpx.

Для создания файла gpx в Android лучшим выбором будет использование библиотеки. Большинство из них могут помочь вам выполнить все вышеперечисленные операции.

Я использую io.jenetics.jpx в своем проекте android, и он отлично работает.

XML не поддерживает добавляемые элементы. Если вы хотите сгенерировать файл gpx во время регистрации, вы должны сделать это в доступной форме, такой как любой тип Serializable. После окончания регистрации вы можете создать действительный файл GPX из файла сериализации.

WayPoint в jpx - это тип Serializable, я его использую.

Вы также можете использовать Android Location, который реализует Parcelable, реализацию android, такую ​​как Serializable.

мой код:

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. Но он был перенесен в Java 6 его создателем Стивеном Колебурном, а также перенесен в раннюю версию android в виде библиотеки.

Библиотека находится здесь: JakeWharton / ThreeTenABP - Адаптация обратного порта JSR-310 для Android.

И как использовать: Как использовать ThreeTenABP в Android проекте - StackOverFlow

...