3.3 臺北市公眾區免費無線上網熱點
3.3.1 各區域內部資料解析
由於台北市政府開放資料平台所提供的資料串接格式多為 JSON 檔案格 式,此格式多以文字為基礎且方便讓使用者閱讀。JSON 與 XML 最大的差異在 於 XML 是屬於一個比較完整的標記語言,而 JSON 不是。使用 XML 在程式判 讀與解析上需要花較多的時間,XML 利用標記語言特性提供較好的延展性,如:
Xpath,在擴充功能與資料儲存上面具有較佳的優勢,反觀 JSON 相對於 XML 來說更加輕巧,更適用於網路資料傳輸。
本研究透過 Http 方式取的 JSON 資料,並在手持裝置上進 JSON 檔案解析與 呈現。圖 3-6 為一個 Http URL 連線並取得 JSON 資料的 Java Class,本研究中系 統解析 JSON 檔案皆是使用此 class 完成,完整內容請參考附錄。
//透過 HTTP 取的 JSON Data try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) { e.printStackTrace();
} catch (ClientProtocolException e) { e.printStackTrace();
} catch (IOException e) { e.printStackTrace();
} try {
// utf-8 為編碼方式、8 為 bufferedreadfer size
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) { sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) { }
try { // 解析 String JSON 物件 jObj = new JSONObject(json);
} catch (JSONException e) { }
return jObj; // 回傳 JSON string }
圖 3- 6 Http 連接 URL 取得 JSON 檔案
如圖 3-7,以 7-ELEVEN 區域為例,Server 端透過 MySQL 語法查詢無線上 網熱點資料庫內容,依據表 3-1 取出所有類別欄位(area)為 7-ELEVEN 的資料並 透過 MySQL 轉 JSON 的 Class 進行格式輸出,再將結果直接透過網頁傳值方式 回傳至使用者手持裝置上進行分析。如圖 3-8,系統中也加入 LocationManager 物件來判斷使用者目前所在位置,並透過 LocationListener 介面取得位置是否更 新的資訊,如圖 3-9。
//載入 json class
include('mysql_to_json.class.php');
mysql_connect('localhost', 'database_user', 'database_password');
mysql_select_db('database');
//資料庫編碼方式
mysql_query("SET NAMES 'UTF8'");
mysql_query("SET CHARACTER SET UTF8");
mysql_query("SET CHARACTER_SET_RESULTS=UTF8'");
//SQL 查詢語法
$query = 'SELECT * FROM senven_eleven';
//建立一個 mysql_to_json instance
$mtj = new mysql_to_json($query);
//顯示 JSON 輸出 echo $mtj->get_json();
$mtj = new mysql_to_json();
echo $mtj->set_query($query)->set_cbfunc('loels')->get_json();
圖 3- 7 將 MySQL 查詢結果輸出成 JSON 格式 // 取得 LocationManager 物件
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// 建立 Criteria 物件,求更精準的定位功能 criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
// criteria 回傳最適合的定位名稱, true 代表只回傳目前可提供的定位名稱 String provider = locationManager.getBestProvider(criteria, true);
// 指定的定位名稱取得自己最新位置
Location myLocation = locationManager.getLastKnownLocation(provider);
this.myLocation = myLocation;
圖 3- 8 透過 LocationManager 物件取得目前位置資訊
// listener 物件實作 LocationListener 介面,專門監聽自己位置是否改變 private LocationListener myLocationListener = new LocationListener() {
//若位置改變就更新資訊
public void onLocationChanged(Location location) { myLocation = location;
updateMyLocationInfo(location);
} };
// 判斷自己位置是否改變 protected void onResume() {
super.onResume();
// 當位置改變時讓系統重新擷取最適當的定位方式
String provider = locationManager.getBestProvider(criteria, true);
//透過 LocationListener 來判斷自己位置是否改變,1000=1 秒,10=10 公尺 locationManager.requestLocationUpdates(provider, 1000,
10,myLocationListener);
}
// 畫面切換時即停止更新自己位置 protected void onPause() {
locationManager.removeUpdates(myLocationListener);
super.onPause();
}
圖 3- 9 LocationListener 更新使用者位置
透過 HTTP 取得 JSON Data 資料格式皆屬於字串(String),因此我們必須將 字串格式的經度與緯度轉換成 double 格式,如圖 3-10。因此我們將轉換完成的 值與自己所在位置的經緯度進行距離的計算,並存入陣列中,經由計算完成的數 值單位為公尺,為了方便使用者查詢本系統將此數值轉為公里,如圖 3-11。
double json_lng = Double.parseDouble(lng);
double json_lat = Double.parseDouble(lat);
圖 3- 10 將字串轉換成 double 型態 float[] results = new float[1];
// 計算兩點間的距離(公尺),結果存入 results[0]
Location.distanceBetween(myLocation.getLatitude(), myLocation.getLongitude(), json_lat,json_lng, results);
//將結果公尺除以 1000 轉換成公里
distance = NumberFormat.getInstance().format(results[0]/1000)+"公里";
圖 3- 11 計算兩點之間的距離並換算成公里
當進入單一資料查詢時,畫面會呈現該點位的詳細資料內容並透過 Google String strUri =
"google.streetview:cbll="+wifi_area_latitude+","+wifi_area_longtitude;
//顯示該點位地址
Toast.makeText(SingleTaipeiWifiTrackActivity.this, wifi_area_address, Toast.LENGTH_LONG).show();
//利用 Intent 方式開啟 Google Map 街景圖
Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(strUri));
startActivity(intent);
圖 3- 12 透過 Intent 方式啟動 Google Map 街景圖 // 取得自己位置緯經度
double fromLat = myLocation.getLatitude();
double fromLng = myLocation.getLongitude();
//取的目的地位置經緯度
double toLat = Double.parseDouble(wifi_area_latitude);
double toLng = Double.parseDouble(wifi_area_longtitude);
direct(fromLat, fromLng, toLat, toLng);
// 開啟 Google 地圖應用程式來完成導航
private void direct(double fromLat, double fromLng, double toLat, double toLng) {
// 設定前往的 Uri,saddr-出發地緯經度;daddr-目的地緯經度 String uriStr = String.format(
"http://maps.google.com/maps?saddr=%f,%f&daddr=%f,%f", fromLat, fromLng, toLat, toLng);
Intent intent = new Intent();
// 指定 Google 地圖應用程式
intent.setClassName("com.google.android.apps.maps",
"com.google.android.maps.MapsActivity");
// ACTION_VIEW-呈現資料給使用者觀看
intent.setAction(android.content.Intent.ACTION_VIEW);
// 將 Uri 資訊附加到 Intent 物件上 intent.setData(Uri.parse(uriStr));
startActivity(intent);
}
圖 3- 13 透過 Intent 啟動 Google Map 導航