在Android应用程序中使用GeoServer的getTileURL方法

8
我们刚开始在Android上使用Google Maps,并设置了GeoServer来提供瓦片,我们希望将其作为地图覆盖层添加。到目前为止,我已经按照一些教程和参考材料入门。 问题:在TileProviderFactory中的getTileUrl函数中生成的url确实返回一个png图像,当我设置断点并将url复制粘贴到浏览器中时,但它不会作为叠加层加载到Android设备地图上。据我所见,没有任何错误,并且阅读了this之后,我不确定是否会有任何错误,因为他们已经指出错误被静音了。

我想知道是您是否能够看到我的代码中是否存在任何明显的问题,或者是否有任何调试建议,以便我能够确定应用程序是否正在与我的GeoServer通信以检索图像。我已查看了GeoServer上的日志,似乎只有我的浏览器请求正在进行,而Android没有发送任何请求(这有点难以确定,因为我们也有其他应用程序使用该服务器)。Android手机通过wifi和蜂窝连接,并启用了GPS。作为最后的手段,我尝试更改了瓦片叠加层zIndex并将其设置为可见,但这似乎没有产生任何影响。

编辑:此时Android设备绝对没有与GeoServer通信。

编辑2:可以从网站(如this)加载静态图像作为覆盖层,并发现在测试HTTP请求到形成的URL时出现以下异常:

W/System.err(10601): java.net.SocketException: The operation timed out
W/System.err(10601): at org.apache.harmony.luni.platform.OSNetworkSystem
     .connectStreamWithTimeoutSocketImpl(Native Method)
W/System.err(10601): at org.apache.harmony.luni.net.PlainSocketImpl
     .connect(PlainSocketImpl.java:244)
W/System.err(10601): at org.apache.harmony.luni.net.PlainSocketImpl
     .connect(PlainSocketImpl.java:533)
W/System.err(10601): at java.net.Socket
     .connect(Socket.java:1074)
W/System.err(10601): at org.apache.http.conn.scheme.PlainSocketFactory
     .connectSocket(PlainSocketFactory.java:119)

Thanks.

MapTestActivity

public class MapTestActivity extends FragmentActivity
    implements LocationListener, LocationSource{

    private GoogleMap mMap;
    private OnLocationChangedListener mListener;
    private LocationManager locationManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map_test);     
        setupLocationManager();     
        setupMapIfNeeded();
    }

    private void setupLocationManager() {
        this.locationManager = 
            (LocationManager) getSystemService(LOCATION_SERVICE);

        if (locationManager != null) {
            boolean gpsIsEnabled = locationManager.isProviderEnabled(
                    LocationManager.GPS_PROVIDER);
            boolean networkIsEnabled = locationManager.isProviderEnabled(
                    LocationManager.NETWORK_PROVIDER);

            if(gpsIsEnabled) {
                this.locationManager.requestLocationUpdates(
                    LocationManager.GPS_PROVIDER, 5000L, 10F, this);
            }
            else if(networkIsEnabled) {
                this.locationManager.requestLocationUpdates(
                    LocationManager.NETWORK_PROVIDER, 5000L, 10F, this);
            }
            else {
                //Show an error dialog that GPS is disabled...
            }
        }
        else {
            // Show some generic error dialog because 
            // something must have gone wrong with location manager.
        }
    }

    private void setupMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the
        // map.
        if (mMap == null) {
            // Try to obtain the map from the SupportMapFragment.
            mMap = ((SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map)).getMap();
            // Check if we were successful in obtaining the map.
            if (mMap != null) {
                setUpMap();
            }
            mMap.setLocationSource(this);
        }
    }

    private void setUpMap() {
        // TODO Auto-generated method stub
        mMap.setMyLocationEnabled(true);
        TileProvider geoServerTileProvider = TileProviderFactory
            .getGeoServerTileProvider();
        TileOverlay geoServerTileOverlay = mMap.addTileOverlay(
            new TileOverlayOptions()
                .tileProvider(geoServerTileProvider)
                .zIndex(10000)
                .visible(true));
    }
    // Non-relevant listener methods removed
}

瓷砖提供程序工厂

public class TileProviderFactory {

    public static GeoServerTileProvider getGeoServerTileProvider() {

        String baseURL = "mytileserver.com";
        String version = "1.3.0";
        String request = "GetMap";
        String format = "image/png";
        String srs = "EPSG:900913";
        String service = "WMS";
        String width = "256";
        String height = "256";
        String styles = "";
        String layers = "wtx:road_hazards";

        final String URL_STRING = baseURL + 
                "&LAYERS=" + layers + 
                "&VERSION=" + version + 
                "&SERVICE=" + service + 
                "&REQUEST=" + request + 
                "&TRANSPARENT=TRUE&STYLES=" + styles + 
                "&FORMAT=" + format + 
                "&SRS=" + srs + 
                "&BBOX=%f,%f,%f,%f" + 
                "&WIDTH=" + width + 
                "&HEIGHT=" + height;


        GeoServerTileProvider tileProvider = 
            new GeoServerTileProvider(256,256) {

            @Override
            public synchronized URL getTileUrl(int x, int y, int zoom) {
                try {       

                    double[] bbox = getBoundingBox(x, y, zoom);

                    String s = String.format(Locale.US, URL_STRING, bbox[MINX], 
                            bbox[MINY], bbox[MAXX], bbox[MAXY]);

                    Log.d("GeoServerTileURL", s);

                    URL url = null;

                    try {
                        url = new URL(s);
                    } 
                    catch (MalformedURLException e) {
                        throw new AssertionError(e);
                    }

                    return url;
                }
                catch (RuntimeException e) {
                    Log.d("GeoServerTileException", 
                        "getTile x=" + x + ", y=" + y + 
                        ", zoomLevel=" + zoom + 
                        " raised an exception", e);
                    throw e;
                }

            }
        };
        return tileProvider;
    }
}

GeoServerTileProvider

public abstract class GeoServerTileProvider extends UrlTileProvider{

    // Web Mercator n/w corner of the map.
    private static final double[] TILE_ORIGIN = 
        {-20037508.34789244, 20037508.34789244};
    //array indexes for that data
    private static final int ORIG_X = 0; 
    private static final int ORIG_Y = 1; // "

    // Size of square world map in meters, using WebMerc projection.
    private static final double MAP_SIZE = 20037508.34789244 * 2;

    // array indexes for array to hold bounding boxes.
    protected static final int MINX = 0;
    protected static final int MINY = 1;
    protected static final int MAXX = 2;
    protected static final int MAXY = 3;

    public GeoServerTileProvider(int width, int height) {
        super(width, height);
    }

    // Return a web Mercator bounding box given tile x/y indexes and a zoom
    // level.
    protected double[] getBoundingBox(int x, int y, int zoom) {
        double tileSize = MAP_SIZE / Math.pow(2, zoom);
        double minx = TILE_ORIGIN[ORIG_X] + x * tileSize;
        double maxx = TILE_ORIGIN[ORIG_X] + (x+1) * tileSize;
        double miny = TILE_ORIGIN[ORIG_Y] - (y+1) * tileSize;
        double maxy = TILE_ORIGIN[ORIG_Y] - y * tileSize;

        double[] bbox = new double[4];
        bbox[MINX] = minx;
        bbox[MINY] = miny;
        bbox[MAXX] = maxx;
        bbox[MAXY] = maxy;
        return bbox;
    }
}
1个回答

8
这实际上是一个网络问题,与我的实现完全无关,而我的实现是“正确”的。我想这个问题会成为其他刚开始使用Android + GeoServer实现的人的一个很好的例子,所以我会保留它。

你好,能指导我如何在Android应用中实现瓦片缓存过程,以便离线显示Google地图吗? 根据我的经验,我已经搜索到了使用asset文件夹上下文实现customTileProvider()的方法, 但是我不确定是否需要放置任何类型的瓦片文件,还是会在地图在线加载时自动下载瓦片,然后缓存并可供离线使用。 - Abdul Wahab
@AbdulWahab 抱歉,自从2013年以来我就没有再做过这个项目了,而且已经忘记了大部分实现细节。你最好找一个对这项技术更为熟悉的人。祝你好运 :)。 - sugarwaffle
你能否在问题中提到的用例中使用osmdroid? - Arjun Issar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接