×
Namespaces

Variants
Actions

Archived:J2ME Google 地圖 API

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

文章
翻译:
最后由 hamishwillee 在 16 Aug 2013 编辑

Archived.png存档: 这篇文章是存档,因为考虑到今天它与第三方开发者建立商业解决方案不相关。

Since this article was written, alternative Map Tile caching solutions for Java ME have become available. Map Tile caching solutions such as the Nokia Maps API for Java ME have several advantages over static mapping solutions such as the static Google Maps API including:

  • Static mapping services such as the Google Static Maps API or Nokia's RESTful Map API do not cache or tile the images when requested, therefore each request involves a round trip to the server. If the map on a mobile application needs to be refreshed at any time, using a caching library will result in a reduction in network traffic after around three maps have been displayed. An explanation of this can be found here
  • As the name implies, Google's Static Maps API can only retrieve over http static images for a requested coordinate point, image size, image type and zoom level. Newer libraries offer additional functionality out of the box offering dynamic Map content and touch support, where the user can move around his/her current position, zoom in, zoom out, modify the view mode to satellite or translate an address to a coordinate point and show that on the map, among others. This abstraction of the underlying functionality is hidden from the developer,os much less coding is needed in order to achieve the same result .

Additionally the following points apply in favour of Nokia Maps when comparing to Google Maps:

  • No legal restrictions of using the API outside a web browser application or need to provide a link to the native Google Maps App (if there is one), or to Google Maps (if there isn't one). See Terms of Service below.
  • Higher free daily request limits. Nokia Maps API for Java ME supports up to 50,000 render requests per day and per unique IP address (as of January 2012), for Nokia Developer registered users (free of charge) while the limit for Google's Static Maps API is currently 1000 unique (different) image requests per viewer per day.
An article with the same functionality, written with Nokia Maps API for Java ME, that uses much less code can be found here

這裡有一個簡單的函式庫來查詢Google地圖,它有下面的功能:

  • 地理編碼定址到其地理座標
  • 擷取給定尺寸、格式及畫面遠近的靜態圖片

這個API有一個實例,你可以在這裡檢查:Java ME Google Maps API sample MIDlet

Contents

取得你自己的Google地圖API Key

注意:用免費的Google地圖API Key的程式使用會違反Google的條款和條件 (10.8節),假如你想要使用Google地圖API在上面的範例中,你應該購買企業許可證。

要使用下面的程式碼,你應該取得你自己的Google地圖API Key,假如你沒有API key,你只能照著下面的操作:如何在手機應用程式中使用Google地圖資料

使用代理伺服器來存取Google地圖服務

注意:這個主題(代理的使用)可能不需要,我們仍然探討一下..
當你註冊取得Google地圖API key時,你可以輸入位址,這個位址使用那個key能夠存取地圖服務,因此,你應該設定代理伺服器在那個位址上,這樣就能從你的行動用戶端收到HTTP請求,轉發給Google地圖服務,收回Google的回饋反應。

在下面的程式碼裡你應該發送下面的請求:

  • http://www.yourserver.com/error.html 請求 http://maps.google.com/maps/geo
  • http://www.yourserver.com/error.htmlhttp://maps.google.com/staticmap

原始碼:GoogleMaps 類別

import java.io.ByteArrayOutputStream; 
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Image;
 
public class GoogleMaps {
private static final String URL_UNRESERVED =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789-_.~";
private static final char[] HEX = "0123456789ABCDEF".toCharArray();
 
// these 2 properties will be used with map scrolling methods. You can remove them if not needed
public static final int offset = 268435456;
public static final double radius = offset / Math.PI;
 
private String apiKey = null;
 
public GoogleMaps(String key) {
apiKey = key;
}
 
public double[] geocodeAddress(String address) throws Exception {
byte[] res = loadHttpFile(getGeocodeUrl(address));
String[] data = split(new String(res, 0, res.length), ',');
 
if (data[0].compareTo("200") != 0) {
int errorCode = Integer.parseInt(data[0]);
throw new Exception("Google Maps Exception: " + getGeocodeError(errorCode));
}
 
return new double[] {
Double.parseDouble(data[2]), Double.parseDouble(data[3])
};
}
 
public Image retrieveStaticImage(int width, int height, double lat, double lng, int zoom,
String format) throws IOException {
byte[] imageData = loadHttpFile(getMapUrl(width, height, lng, lat, zoom, format));
 
return Image.createImage(imageData, 0, imageData.length);
}
 
private static String getGeocodeError(int errorCode) {
switch (errorCode) {
case 400:
return "Bad request";
case 500:
return "Server error";
case 601:
return "Missing query";
case 602:
return "Unknown address";
case 603:
return "Unavailable address";
case 604:
return "Unknown directions";
case 610:
return "Bad API key";
case 620:
return "Too many queries";
default:
return "Generic error";
}
}
 
private String getGeocodeUrl(String address) {
return "http://maps.google.com/maps/geo?q=" + urlEncode(address) + "&output=csv&key="
+ apiKey;
}
 
private String getMapUrl(int width, int height, double lng, double lat, int zoom, String format) {
return "http://maps.google.com/maps/api/staticmap?center=" + lat + "," + lng + "&format="
+ format + "&zoom=" + zoom + "&size=" + width + "x" + height + "&key=" + apiKey;
}
 
private static String urlEncode(String str) {
StringBuffer buf = new StringBuffer();
byte[] bytes = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF(str);
bytes = bos.toByteArray();
} catch (IOException e) {
// ignore
}
for (int i = 2; i < bytes.length; i++) {
byte b = bytes[i];
if (URL_UNRESERVED.indexOf(b) >= 0) {
buf.append((char) b);
} else {
buf.append('%').append(HEX[(b >> 4) & 0x0f]).append(HEX[b & 0x0f]);
}
}
return buf.toString();
}
 
private static byte[] loadHttpFile(String url) throws IOException {
byte[] byteBuffer;
 
HttpConnection hc = (HttpConnection) Connector.open(url);
try {
hc.setRequestMethod(HttpConnection.GET);
InputStream is = hc.openInputStream();
try {
int len = (int) hc.getLength();
if (len > 0) {
byteBuffer = new byte[len];
int done = 0;
while (done < len) {
done += is.read(byteBuffer, done, len - done);
}
} else {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[512];
int count;
while ( (count = is.read(buffer)) >= 0 ) {
bos.write(buffer, 0, count);
}
byteBuffer = bos.toByteArray();
}
} finally {
is.close();
}
} finally {
hc.close();
}
 
return byteBuffer;
}
 
private static String[] split(String s, int chr) {
Vector res = new Vector();
 
int curr;
int prev = 0;
 
while ( (curr = s.indexOf(chr, prev)) >= 0 ) {
res.addElement(s.substring(prev, curr));
prev = curr + 1;
}
res.addElement(s.substring(prev));
 
String[] splitted = new String[res.size()];
res.copyInto(splitted);
 
return splitted;
}
}

地圖捲動的使用方法

假如你需要捲動你的地圖,你將需要對你的靜態圖片計算一個新的中心,下面的adjust()方法傳回新的地圖中心的經緯度,接受以下的參數:

  • 目前中心的經度緯度座標
  • 新地圖中心的deltaXdeltaY像素值
  • 新地圖畫面遠近程度


原來的程式碼是用JavaScript寫的,可以在:http://home.provide.net/~bratliff/adjust.js下載

注意:如果你使用的是CLDP 1.0的話,要使用下面的方法,你必須將MicroFloat函式庫可在這裡下載:MicroFloat網站含括到你的專案裡,現在在CLDP 1.1已經支援float及double了!

public double[] adjust(double lat, double lng, int deltaX, int deltaY, int z)
{
return new double[]{
XToL(LToX(lng) + (deltaX<<(21-z))),
YToL(LToY(lat) + (deltaY<<(21-z)))
};
}
double LToX(double x)
{
return round(offset + radius * x * Math.PI / 180);
}
 
double LToY(double y)
{
return round(
offset - radius *
Double.longBitsToDouble(MicroDouble.log(
Double.doubleToLongBits(
(1 + Math.sin(y * Math.PI / 180))
/
(1 - Math.sin(y * Math.PI / 180))
)
)) / 2);
}
 
double XToL(double x)
{
return ((round(x) - offset) / radius) * 180 / Math.PI;
}
 
double YToL(double y)
{
return (Math.PI / 2 - 2 * Double.longBitsToDouble(
MicroDouble.atan(
MicroDouble.exp(Double.doubleToLongBits((round(y)-offset)/radius))
)
)) * 180 / Math.PI;
}
double round(double num)
{
double floor = Math.floor(num);
 
if(num - floor >= 0.5)
return Math.ceil(num);
else
return floor;
}

原始碼:範例使用

J2me google maps.jpg
要使用這個類別,首先先用你的API金鑰:

GoogleMaps gMap = new GoogleMaps("API_KEY");

要地理編碼一個地址,你可以使用geocodeAddress()方法:

double[] lanLng = gMap.geocodeAddress("中壢市永泰街129號");

要擷取地圖圖像:

Image map = gMap.retrieveStaticImage(320, 240, 51.510605, -0.130728, 8, "png32");


相关链接

This page was last modified on 16 August 2013, at 09:41.
312 page views in the last 30 days.