Skip to content
CrossFly is 100% open sourceFollow us on GitHub
CrossFlyCrossFly
Get started

This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.

How to get the GPS position (latitude/longitude)

Purpose. Get the device’s latitude/longitude. For a one-off read use Location

  • retrieveGPSData(); for continuous tracking use GPSThread, which manages the thread for you.

APIs used

  • new Location() throws IOException — opens the GPS (high precision by default). There’s also new Location(int precision) with Location.HIGH_GPS_PRECISION (GPS only) or Location.LOW_GPS_PRECISION (GPS + Google Play Services / radio / wifi).
  • boolean retrieveGPSData() — updates the static fields; returns true if it got valid data, false on low signal (reason in Location.lowSignalReason).
  • Location.getLatitude() / getLongitude() (static) — coordinates; equal Location.INVALID without signal.
  • Location.velocity (in knots), Location.pdop (precision dilution), Location.satellites, Location.direction — static fields.
  • void stop() — mandatory: closes the native API and releases the single instance. There can only be one Location open at a time (the constructor throws IOException if one already exists).
  • GPSThread(boolean highPrecision, int intervalInMS, Runnable onLocation, RunnableWith<Exception> onError) — daemon thread that starts on its own in the constructor; stopGps() stops it and waits for it to finish.

Cautions. The coordinate fields are static — only one active read at a time. Always validate against Location.INVALID and check the pdop before trusting the position (LOW may return 30m–1500m+). Call stop() when done (the GPSThread does it for you on every cycle).

Complete example (copy, paste, and run)

package com.exemplo;

import dev.crossfly.ui.*;                   // Window, Component, Button, Label
import dev.crossfly.ui.layout.*;            // VerticalLayout
import dev.crossfly.device.*;               // Location, Device

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label resultado = new Label("");
      add(LAY_AUTO, resultado);

      Button acao = new Button("Obter GPS");
      acao.onAction(c ->
      {
         // One-off reading (outside the paint thread) — always in try/finally to guarantee stop()
         new Thread(() ->
         {
            Location loc = null;
            try
            {
               loc = new Location();                              // opens the GPS (only 1 at a time)
               for (int i = 0; i < 120 && !loc.retrieveGPSData(); i++)
                  Device.sleep(500);                              // waits up to ~60s for a fix
               double lat = Location.getLatitude();
               double lon = Location.getLongitude();
               if (lat != Location.INVALID && lon != Location.INVALID)
                  Component.onUI(() -> resultado.setText("Lat " + lat + " / Lon " + lon));
               else
                  Component.onUI(() -> resultado.setText("Sem sinal de GPS"));
            }
            catch (java.io.IOException e)
            {
               // a Location was already open, or failed to open the GPS
               Component.onUI(() -> resultado.setText("Erro: " + e.getMessage()));
            }
            finally
            {
               if (loc != null) loc.stop();                       // REQUIRED
            }
         }).start();
      });
      add(LAY_AUTO, acao);
   }
}

The snippet below shows only the core. To run it, place it in the MainWindow skeleton above.

Minimal snippet

// verified at source: Location.java (Location(), retrieveGPSData, getLatitude/Longitude, INVALID, stop); GPSThread.java (constructor, stopGps)
import dev.crossfly.device.*;              // Location
import dev.crossfly.core.*;                // GPSThread
import dev.crossfly.ui.*;                  // Component (onUI)

// 1) One-off reading (outside the paint thread) — always in try/finally to guarantee stop()
new Thread(() -> {
   Location loc = null;
   try {
      loc = new Location();                              // opens the GPS (only 1 at a time)
      for (int i = 0; i < 120 && !loc.retrieveGPSData(); i++)
         Device.sleep(500);                              // waits up to ~60s for a fix
      double lat = Location.getLatitude();
      double lon = Location.getLongitude();
      if (lat != Location.INVALID && lon != Location.INVALID)
         Component.onUI(() -> mostrarPosicao(lat, lon)); // return outside the paint thread
   } catch (java.io.IOException e) {
      // a Location was already open, or failed to open the GPS
   } finally {
      if (loc != null) loc.stop();                       // REQUIRED
   }
}).start();

// 2) Continuous tracking — GPSThread starts on its own; callbacks outside the paint thread
GPSThread gps = new GPSThread(true, 5000,                // high precision, every 5s
   () -> {
      double lat = Location.getLatitude(), lon = Location.getLongitude();
      Component.onUI(() -> atualizarMapa(lat, lon));
   },
   err -> Component.onUI(() -> mostrarErro(err.getMessage())));
// ... when finished:
gps.stopGps();

Go deeper

Was this page helpful?