使用 gps 在离线模式下显示当前位置

Posted

技术标签:

【中文标题】使用 gps 在离线模式下显示当前位置【英文标题】:Showing current location in offline mode with gps 【发布时间】:2018-05-19 06:16:14 【问题描述】:

您好,我对 android 有点陌生,我一直想开发一个 android 应用程序,该应用程序应该在离线模式下在地图(如谷歌地图)上显示用户的当前位置。我可以只用 GPS 显示位置而没有互联网连接吗?不用说,这个离线的东西对我来说至关重要。任何帮助,将不胜感激。提前通知

【问题讨论】:

Can I show the location with just GPS and without Internet connection。是的当然。 GPS不需要互联网。离线地图也没有。 但谷歌地图默认不离线,如果用户请求只能下载小块地图(甚至不能被外部地图 API afaik 使用......):-( 然后使用 Openstreetmap 和 OsmDroid。 你不知道openstreetmap?好吧看看:openstreetmap.org/… 在您的设备上安装 OsmAnd 和 Maps.me。他们全部离线使用openstreetmap。还有更多。然后制作自己的应用程序。你可以做得更好。并使用他们已经下载的相同地图。 【参考方案1】:

您可以获得 GPS 位置(尽管如果没有 GSM 塔定位,它的精确度会降低)。但是,地图部分可能很棘手。您可以在您的应用程序中使用Google Maps API,例如 MapActivity,但地图本身必须从网络下载。

因此,您将需要一些自定义解决方案,可能通过与 Google 地图不同的地图提供商。

您也许可以做一些不同的事情 - 在您的应用中获取位置,然后使用 Intent 打开 Google 地图,传递接收到的坐标。这应该允许用户使用他们可能拥有的任何离线存储的地图。

【讨论】:

Tnx.你能说出一些地图供应商的名字吗? 不是真的,我只用过谷歌地图,你得在这里做一些研究 这个,例如,看起来很有希望:github.com/mapsme/api-android (although it will be less precise without GSM tower localisation)。一点都不。 GSM塔非常不精确。最好不要。没有什么比 GPS 更好了。 听说过 GSM 三角测量吗?当然,精确定位需要 GPS,但 GSM 有很大帮助【参考方案2】:

您可以通过NmeaListener 或更好的OnNmeaMessageListener(恕我直言,它更复杂)从 GPS 获取原始NMEA 数据,然后像这样解析RMC sentence:

public class CustomNmeaListener implements GpsStatus.NmeaListener

    private GoogleMap mGoogleMap;
    private Marker mMarkerPosition = null;
    private BitmapDescriptor mMarkerMoveDescriptor;
    private BitmapDescriptor mMarkerStopDescriptor;

    public CustomNmeaListener(GoogleMap googleMap, int markerMoveResource, int markerStopResource)
        this.mGoogleMap = googleMap;

        mMarkerMoveDescriptor = BitmapDescriptorFactory.fromResource(markerMoveResource);
        mMarkerStopDescriptor = BitmapDescriptorFactory.fromResource(markerStopResource);
    

    @Override
    public void onNmeaReceived(long timestamp, String nmea) 
        double latitude;
        double longitude;
        float speed;
        float angle;

        // parse NMEA RMC sentence
        // Example $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
        //   nmea    [0]   [1]  [2]  [3]   [4]   [5]   [6] [7]   [8]   [9]   [10]  [11]
        if (nmea.startsWith("$GPRMC")) 

            String[] nmeaParts = nmea.split(",");

            // if RMC data valid ("active")
            if (nmeaParts[2].equals("A")) 
                latitude = parseLatitude(nmeaParts[3], nmeaParts[4]);
                longitude = parseLongitude(nmeaParts[5], nmeaParts[6]);
                speed = parseSpeed(nmeaParts[7]);
                angle = parseAngle(nmeaParts[8]);

                // remove marker on "old" position
                if (mMarkerPosition != null) 
                    mMarkerPosition.remove();
                

                MarkerOptions positionMarkerOptions;

                if (speed > 0) 
                    positionMarkerOptions = new MarkerOptions()
                            .position(new LatLng(latitude, longitude))
                            .icon(mMarkerMoveDescriptor)
                            .anchor(0.5f, 0.5f)
                            .rotation(angle);
                 else 
                    positionMarkerOptions = new MarkerOptions()
                            .position(new LatLng(latitude, longitude))
                            .icon(mMarkerStopDescriptor)
                            .anchor(0.5f, 0.5f)
                            .rotation(0);
                
                mMarkerPosition = mGoogleMap.addMarker(positionMarkerOptions);
            
        

    

    static float parseLatitude(String lat, String sign) 
        float latitude = Float.parseFloat(lat.substring(2)) / 60.0f;
        latitude +=  Float.parseFloat(lat.substring(0, 2));
        if(sign.startsWith("S")) 
            latitude = -latitude;
        
        return latitude;
    

    static float parseLongitude(String lon, String sign) 
        float longitude = Float.parseFloat(lon.substring(3)) / 60.0f;
        longitude +=  Float.parseFloat(lon.substring(0, 3));
        if(sign.startsWith("W")) 
            longitude = -longitude;
        
        return longitude;
    

    static float parseSpeed(String knots) 
        float speed;
        try 
            speed = Float.parseFloat(knots);
         catch (Exception e) 
            speed = 0;
        
        return speed;
    

    static float parseAngle(String ang) 
        float angle;
        try 
            angle = Float.parseFloat(ang);
         catch (Exception e) 
            angle = 0;
        
        return angle;
    

并在requestLocationUpdates()调用时设置RMC句子间隔

try 
    mLocationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            <your_update_interval>,
            LOCATION_DISTANCE,
            this
    );
  catch (java.lang.SecurityException ex) 
    Log.d(TAG, "fail to request location update, ignore", ex);
 

对于地图服务,您应该使用自定义解决方案,因为即使是离线地图,Google 地图也需要互联网连接,至少要进行 MAPS API KEY 检查。作为第一种方法,您可以使用简单的ImageView 和地图截图。

【讨论】:

这可以让您获取位置,但如果它处于离线状态,则不会在地图上显示它,因为不会下载地图。 @Kelevandos 只需使用ImageView 与地图截图。 等等什么?什么截图?整个地球,放大?你希望这是什么分辨率? Integer.MAX_VALUE:Integer.MAX_VALUE? 截图对我没有帮助。我需要一张完整的地图 @Kelevandos 当然是目标区域的截图。您无法在移动设备上拥有具有适当缩放级别的整个地球的平铺地图。

以上是关于使用 gps 在离线模式下显示当前位置的主要内容,如果未能解决你的问题,请参考以下文章

使用 Google Play 服务我可以在离线模式下获取最新位置吗(FusedLocationProvider Api)

在离线模式下获取当前日期

iOS SKMaps 下载的地图包未在离线模式下显示

在离线模式下获得响应

如何在离线模式下使用 Cordova Geolocation 插件

PDF文件阅读问题仅在离线模式下快速