Location Based Services - LBS

Slides:



Advertisements
Similar presentations
Location Based Services - LBS Google Maps 路徑規劃與導航 1.
Advertisements

第13章 繪圖與多媒體 13-1 顯示圖檔-行動相簿 13-2 音樂播放-音樂播放器 13-3 影片播放-視訊播放器
MVC Servlet与MVC设计模式.
實驗五:多媒體播放器選單介面.
Part 2 開發Android應用程式的流程
位置與地圖應用 此投影片為講解Android如何取得定位經緯度和使用Google Map地圖.
第二章 JAVA语言基础.
Android + Web Service 建國科技大學 資管系 饒瑞佶 2017/3 V1.
ArrayAdapter & Spinner
Location Based Services - LBS
Chaper 12 網路服務.
Android App 系統開發教學 Luna 陳雯琳 2014/12/18
厦门大学数据库实验室 报告人:谢荣东 导师:林子雨 2014年8月30日
實驗四:單位轉換程式.
Chapter 13 Android 實戰演練.
Android + JUnit 單元測試 建國科技大學資管系 饒瑞佶 2012/8/19V4.
實驗十三:顯示目前經緯度位置.
Ch06 再談選單元件 物件導向系統實務.
使用Android控制Arduino 史先强
7.3 Intent传值.
第10章 App微信分享的实现 倚动实验室.
Android資料庫處理 Android智慧型手機程式設計 程式設計與應用班 建國科技大學 資管系 饒瑞佶 2012/4 V1
第11章 Android GPS位置服务与地图编程
第9章 位置服务与地图应用.
第一个Android程序 本讲大纲: 1、创建Android应用程序 2、Android项目结构说明 3、运行Android应用程序
第8章 Android内容提供者(ContentProvider)应用
Chapter 6 Advanced UI Design.
崑山科技大學資訊管理系 伺服網頁程式設計 系統開發細部流程 教師:游峰碩.
Android智慧型手機程式設計實務應用班
Chapter 7 Android應用元件 Android應用元件可以幫助我們獲得系統資源訊息(ActivityManager)、提供系統服務(Service)、搜尋系統服務(SearchManager)、監聽Intent訊息(Broadcast Receiver)以及資料共享(ContentProvider和ContentResolver)。
Android介面設計 Android智慧型手機程式設計 建國科技大學 資管系 饒瑞佶 2012/4 V1 2012/8 V2
本單元介紹何謂變數,及說明變數的宣告方式。
Chapter 6 進階UI設計.
第4章 Android生命周期.
第9章 使用意圖啟動活動與內建應用程式 9-1 意圖的基礎 9-2 使用意圖啟動活動
ANDROID PROGRAMMING2.
CH7 佈局、按鈕與文字編輯元件.
Android + Service 建國科技大學 資管系 饒瑞佶.
Android 基礎.
實驗十四:顯示與控制地圖.
第2讲 移动应用开发基础知识(二) 宋婕
RecyclerView and CardView
建立Android新專案 Android智慧型手機程式設計 程式設計與應用班 建國科技大學 資管系 饒瑞佶 2012/4 V1
第8章 Service解析.
第6章 建立Android使用介面 6-1 介面元件的基礎 6-2 Android的事件處理 6-3 按鈕元件 6-4 文字元件
Location Based Services - LBS
Java程序设计 第2章 基本数据类型及操作.
第10章 GPS位置服务与地图编程.
實驗十一:待辦事項程式 (儲存在手機上).
主编:钟元生 赵圣鲁.
透過YouTuBe API取得資料 建國科技大學 資管系 饒瑞佶 2018/1 V1.
Chapter 5 Basic UI Design.
Android視窗介面 建國科技大學 資管系 饒瑞佶 2010/10.
實驗九:延續實驗八, 製作一個完整音樂播放器
Location Based Services - LBS
進階UI元件:Spinner與接合器 靜宜大學資管系 楊子青
補間動畫 (Tween Animation) 靜宜大學資管系 楊子青
第二章 Java基本语法 讲师:复凡.
第二章 Java语法基础.
Android視窗介面 建國科技大學 資管系 饒瑞佶 2010/10.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
RecyclerView and CardView
Android Speech To Text(STT)
用Intent啟動程式中的其他Activity、運用WebView顯示網頁 靜宜大學資管系 楊子青
第2章 Java语言基础.
讀取網路資料及JSON開放資料 靜宜大學資管系 楊子青
第二章 Java基础语法 北京传智播客教育
Part 8 Broadcast Receiver、Service和App Widget
進階UI元件:Spinner與接合器 靜宜大學資管系 楊子青
Presentation transcript:

Location Based Services - LBS 系統實例 – 單車練習曲 講師:蘇怡仁

Outline 系統簡介 系統規劃 系統環境建置 單車練習曲建置

Chapter1. 系統簡介

系統簡介 1. 創作動機 近年來單車活動逐漸盛行,車隊活動的人員管理以及安全這兩方面將是個重要議題,為了解決這兩方面的問題,便開發了這項系統來降低意外事件的發生。

系統簡介 1. 創作動機 5.2 km 在團隊單車行徑中,難以掌握各個團員的即時狀況 居然完全沒人發現我摔車了

系統簡介 1. 創作動機 單車練習曲因應而生 因此若透過單車練習曲來辦活動的話則可以幫助解決這個問題

系統簡介 2. 系統功能 會員註冊 好友清單 行動好友 使用者 活動建立 邀請參加 單車活動 顯示路線 隊員位置 路線規劃 位置異常

系統簡介 3. 系統架構 Client Web Server Web Service Database Internet

系統簡介 4. 系統操作流程 會員註冊 好友清單 行動好友 暱稱 登入 1. 輸入使用者名稱 2. 點選登入 3. 透過 simid 完成註冊, 若已註冊則僅更新名稱 登入頁面 朋友清單 活動 4. 點選朋友清單 功能選單 朋友清單 Andy Marcus Marry 5. 列出所已註冊過的人

系統簡介 4. 系統操作流程 活動建立 邀請參加 單車活動 朋友清單 單車活動 1. 點選活動 功能選單 活動清單 夜戰阿里山 燕巢一日遊 阿公店車道 建立活動 2. 點選建立活動 活動新增與邀請 Andy Marcus Marry 5. 輸入活動標題 活動標題 建立 7. 點選建立 6. 選取參與人 下一頁 3. 點擊活動目的地 4. 點選下一頁 活動位置(地圖打點)

系統簡介 4. 系統操作流程 顯示路線 隊員位置 路線規劃 異常偵測 功能選單 活動清單 地圖顯示 3. 顯示規劃路線 異常偵測 與領隊超過一段距離 隊員會由藍色轉紫色 建立活動 夜戰阿里山 朋友清單 燕巢一日遊 2. 選擇參與活動 阿公店車道 單車活動 4. 顯示隊員位置 粉:起點與終點 橘:領隊 黃:自己 藍:其他隊員 紫:狀態異常 1. 點選活動

Chapter2. 系統規劃

系統規劃 1. 系統功能介面規劃 單車活動 3 4 6 7 1 2 5 8

系統規劃 2.ER-Model 1 n m 1 simid name aid aid title Join User Activity simid:varchar 20, 用來記錄手機 sim card ID, 作為 User 的主鍵並當作登入帳號 name:varchar 20, 用來記錄使用者姓名,手機端每次登入即會更新使用者姓名 lat:double, 用來記錄使用者目前位置的(緯度) lng : double, 用來記錄使用者目前位置的(經度) Join aid : int, 用來記錄活度被那些人所參加 simid : varchar 20, 用來記錄使用者參加哪些活動 Activity aid : int (auto_increment), 用來當做 Activity 的主鍵,作為每一個單車活動的編號,設定為自動編號 title : varchar 20, 用來記錄單車活動的標題 direction : text, 紀錄經過 Google Directions 所規劃的路徑編碼 master_simid : varchar 20, 紀錄活動領隊的simid (活動建立者即為領隊) lat lng simid direction master_simid

系統規劃 3. Web Service 規劃 Service 功能描述 需求參數 返回格式 返回參數 備註 user.php 列出所有好友清單 無 json simid name location.php 目前User所在經緯度 lat lng activity.php 列出目前User所參與活動清單 aid title

系統規劃 3. Web Service 規劃 Service 功能描述 需求參數 返回格式 返回參數 備註 updateLocation.php 更新目前 Use經緯度 simid json response lat lng login.php 帳號登入(若沒帳號則會註冊,若有帳號則會更新姓名) name addActivity.php 新增單車活動,與新增邀請好友與紀錄領隊(創建活動者)與規畫路徑功能 title direction master aid friend[simid] 請使用","做間隔 joinUser.php 查詢參與活動人的相關資訊

系統規劃 4.單車練習曲 Use Case Diagram 單車練習曲 Service 使用者 活動申請 地圖打點 上傳使用者 列出會員 <<include>> 活動申請 <<include>> 上傳使用者 位置 列出會員 Service 使用者 Google Maps <<extend>> <<include>> 活動列表 <<include>> 異常偵測 路徑規劃

系統規劃 5.單車練習曲 Class Diagram <<persistent>> User - simid : String - name : String - lat : Double - lng : Double + getName(simid): String + getPosition(simid): String <<persistent>> Join - simid : String - aid : Int + invite(simid,aid) + getParticipants(aid): List + getActivity(simid): List <<persistent>> Activity - aid : Int - title : String - direction : String - master_simid : String + getActivityInfo(aid): Array + getDirection(aid): String 0…* 0…* 1 1 1 1 <<transient>> Background Service + setPosition(simid,aid)

系統規劃 6. 單車練習曲 Sequence Diagram :會員 :參加 :單車活動 Web Android Service getUserList():array getUserList():json return return getLocation(simid):array getLocation(simid):json return return getJoinActivity(simid):array getJoinActivity(simid):json getTitle(aid):String return return return

(title,direction,master,friend[]):boolean 系統規劃 6. 單車練習曲 Sequence Diagram Web Service Android :會員 :參加 :單車活動 login(simid,name):boolean checkUser(simid,name):json return return addActivity (title,direction,master,friend[]):boolean addActivity(title,lat,lng) return:aid addParticipant(aid,friend[]):json return

系統規劃 6. 單車練習曲 Sequence Diagram :會員 :參加 :單車活動 Web Android Service getJoinUser(aid,simid):array getJoinUser(aid,simid):json return:title,direction,master_simid getParticipant(aid) return:array() return

系統規劃 6. 單車練習曲 Sequence Diagram :會員 Android (Background Service) Web updateLocation(simid,lat,lng):boolean updateLocation(simid,lat,lng):json return return

Chapter3. 系統環境建置

系統環境建置 2.建置資料庫 點擊Admin,啟動MySQL管理介面

系統環境建置 2.建置資料庫 1 4 bicyclemaps utf8_general_ci 2 3

系統環境建置 3.建置資料庫欄位 3 user 4 1 2

系統環境建置 2.建置資料庫欄位 1 建立user相關欄位 2

系統環境建置 2.建置資料庫欄位 3 join 3 1 2

系統環境建置 2.建置資料庫欄位 1 建立join相關欄位 2

系統環境建置 2.建置資料庫欄位 3 activity 4 1 2

系統環境建置 2.建置資料庫欄位 1 建立activity相關欄位 2

Chapter4. 單車練習曲建置

單車練習曲建置 3. 權限說明 Uses Permission INTERNET 網路存取權限 ACCESS_FINE_LOCATION GPS定位權限 ACCESS_COARSE_LOCATION 無線網路定位 ACCESS_NETWORK_STATE 允許應用程序訪問有關GSM網絡信息 WRITE_EXTERNAL_STORAGE 允許應用程序寫入外部存儲器

單車練習曲建置 3. 權限說明 Uses Permission Permission MAPS_RECEIVE 允許下載圖資 READ_PHONE_STATE 允許存取 SIM Card 資訊 READ_GSERVICES 允許 API 訪問 Google Web 的服務 Permission MAPS_RECEIVE 允許下載圖資

在其他user-permission底下貼上READ_GSERVICES權限 單車練習曲建置 在其他user-permission底下貼上READ_GSERVICES權限 只有READ_GSERVICES的權限需要透過手動的方式加入到AndroidManifest.xml程式碼當中 2 1 <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>

單車練習曲建置 4. 物件參數設定 value.java 1 2 3 4 5 6 7 8 9 package com.stu.bicycle_maps; 2 public final class value { 3 public static String simid = ""; 4 public static String name = ""; 5 public static String service = 6 "http://localhost/service/bicyclemaps/"; 7 /* 每個頁面可能會用到的參數, 8 都會先宣告在 value 物件當中 9 而 service 參數要設定成自己的位置 /* 10 11 } 打開 value.java

單車練習曲建置 5. 登入功能描述 Android Web Service MainActivity.java 1 Require 將 SIMID 與 NAME 傳送給 Service 後,便可直接登入到功能頁面 Require response simid Web Service name JSON login.php GET 第一次登入會透過SIM CARD ID 當作帳號與輸入姓名來新增一筆帳號,再次登入僅會更新姓名資料 Response

單車練習曲建置 5-1. 登入功能 Service login.php 1 2 3 4 5 6 7 8 9 10 11 if (isset($_GET['simid']) && isset($_GET['name'])) 2 { 3 $simid = mysql_real_escape_string($_GET['simid']); 4 $name = mysql_real_escape_string($_GET['name']); 5 //透過 GET 代入 simid (SIM Card ID) 與 name (名稱) 參數 6 include("../connect.php"); 7 $sql = "SELECT * FROM user WHERE simid = '$simid'"; 8 $result = mysql_query($sql, $link) or die("oops"); 9 //指定查詢 $simid 是否有註冊紀錄,若回傳資料筆數為 0 則表示未註冊 1 則已註冊 10 if(mysql_num_rows($result) != 0) { 11 $sql = "Update user SET name = '$name' WHERE simid = '$simid'";

單車練習曲建置 12 // 若已註冊則更新這個 $simid 的 name 欄位,更改名稱 13 $result = mysql_query($sql, $link) or die("oops"); 14 }else{ 15 $sql = "INSERT INTO user(simid,name,lat,lng) VALUES('$simid','$name','0','0')"; 16 //若未註冊則新增一筆使用者紀錄,預設 lat 與 lng 經緯度位置為 0 17 18 } 19 if($result) { 20 $data['responese'] = 'success'; 21 echo json_encode($data); 22 23 24

單車練習曲建置 5-2. 登入功能 Layout activity_main.xml 1 2 3 4 5 6 7 8 9 10 11 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context=".MainActivity" > 10 <Button 11 android:id="@+id/button1"

單車練習曲建置 12 android:layout_width="wrap_content" 13 android:layout_height="wrap_content" 14 android:layout_alignParentBottom="true" 15 android:layout_centerHorizontal="true" 16 android:layout_marginBottom="78dp" 17 android:text="登入" /> 18 <EditText 19 android:id="@+id/editText1" 20 21 22 android:layout_alignParentTop="true" 23 24 android:layout_marginTop="95dp"

單車練習曲建置 25 android:ems="10" 26 android:inputType="textMultiLine" > 27 <requestFocus /> 28 </EditText> 29 <TextView 30 android:id="@+id/textView1" 31 android:layout_width="wrap_content" 32 android:layout_height="wrap_content" 33 android:layout_alignBottom="@+id/editText1" 34 android:layout_centerHorizontal="true" 35 android:layout_marginBottom="51dp" 36 android:text="名稱" 37 android:textAppearance="?android:attr/textAppearanceLarge" /> 38 </RelativeLayout>

單車練習曲建置 5-3. 登入功能 MainActivity.java 1 2 3 4 5 6 7 8 9 10 11 import org.apache.http.HttpEntity; 3 import org.apache.http.HttpResponse; 4 import org.apache.http.client.HttpClient; 5 import org.apache.http.client.methods.HttpGet; 6 import org.apache.http.impl.client.DefaultHttpClient; 7 import org.apache.http.util.EntityUtils; 8 import android.app.Activity; 9 import android.content.Context; 10 import android.content.Intent; 11 import android.os.Bundle; Android:MainActivity.java 打開 MainActivity.java

單車練習曲建置 12 import android.telephony.TelephonyManager; 13 import android.util.Log; 14 import android.view.View; 15 import android.view.View.OnClickListener; 16 import android.widget.Button; 17 import android.widget.EditText; 18 19 public class MainActivity extends Activity { 20 EditText name; 21 Button login; 22 23 protected void onCreate(Bundle savedInstanceState) { 24 super.onCreate(savedInstanceState);

單車練習曲建置 25 setContentView(R.layout.activity_main); 26 findViwe(); 27 //前置先與 Layout 元件作連結 28 simid(); 29 //取得 SIM Card ID 30 initListener(); 31 32 } 33 public void findViwe() { 34 name = (EditText) findViewById(R.id.editText1); 35 login = (Button) findViewById(R.id.button1); 36 //連結 EditText 與 Button 元件,並給定到參數中 37

單車練習曲建置 38 39 40 41 42 43 44 45 46 47 48 49 50 public void simid() { TelephonyManager manager = 40 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 41 value.simid = manager.getDeviceId(); 42 //透過 TelephonyManager 取得 SimCard ID,存放到 value.simid 43 } 44 45 public void initListener() { 46 login.setOnClickListener(new OnClickListener() { 47 public void onClick(View v) { 48 value.name = name.getText().toString(); 49 login Login = new login(); 50 Login.start();

單車練習曲建置 51 52 53 54 55 並在執行 Login 執行緒後,轉跳功能選擇頁 /* 56 } 57 }); 58 59 60 Intent intent = new Intent(); 52 intent.setClass(MainActivity.this, select.class); 53 startActivity(intent); 54 /* 將 name 當中輸入的字串設定給 value 物件, 55 並在執行 Login 執行緒後,轉跳功能選擇頁 /* 56 } 57 }); 58 59 60 61 62 63

單車練習曲建置 64 class login extends Thread { 65 66 public void run() { 67 super.run(); 68 try { 69 HttpClient client = new DefaultHttpClient(); 70 String url = value.service + "login.php?simid=" + value.simid 71 + "&name=" + value.name; 72 //將 value 物件中的 service 與 simid 與 name 透過 GET 呼叫 login.php 73 HttpGet get = new HttpGet(url); 74 HttpResponse response = client.execute(get); 75 //執行 url 設定的 Login Service 76

單車練習曲建置 77 HttpEntity resEntity = response.getEntity(); 78 String result = EntityUtils.toString(resEntity); 79 //回傳執行的結果並存放在 result 當中 80 } catch (Exception e) { 81 e.printStackTrace(); 82 } 83 84 85 86 87 88 89

單車練習曲建置 6. 功能清單功能描述 Android Web Service 3 select.php 單車活動 select.php backgroundService.php Require 登入後提供兩個按鈕功能選單,並啟動 Background Service 來不斷更新當前位置資訊 (當觸發 Location Change 事件後作更新) 2 simid response lat Web Service lng JSON GET updateLocation.php 更新該 simid 用戶目前所處經緯度位置 Response

單車練習曲建置 6-1. 更新用戶位置資訊 Service updateLocation.php 1 2 3 4 5 6 7 8 9 10 if (isset($_GET['simid']) && isset($_GET['lat']) && isset($_GET['lng'])) { 3 { 4 $simid = mysql_real_escape_string($_GET['simid']); 5 $lat = mysql_real_escape_string($_GET['lat']); 6 $lng = mysql_real_escape_string($_GET['lng']); 7 //透過 GET 代入 simid (SIM Card ID) 與 lat, lng (經緯度)參數 8 include("../connect.php"); 9 $sql = "Update user SET lat = '$lat',lng = '$lng' WHERE simid = '$simid'"; 10 11

單車練習曲建置 12 $result = mysql_query($sql, $link) or die("oops"); 13 //指定查詢 $simid 是否有註冊紀錄,若回傳資料筆數為 0 則表示未註冊 1 則已註冊 14 15 if($result) 16 { 17 $data['responese'] = 'success'; 18 echo json_encode($data); 19 } 20 21 22 23 24

單車練習曲建置 6-2. 功能選單 Layout select.xml 1 2 3 4 5 6 7 8 9 10 11 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:id="@+id/RelativeLayout1" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <Button 7 android:id="@+id/button1" 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:layout_alignParentLeft="true" 11 android:layout_alignParentTop="true"

單車練習曲建置 12 android:layout_marginLeft="105dp" 13 android:layout_marginTop="68dp" 14 android:text="朋友清單" /> 15 <Button 16 android:id="@+id/button2" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:layout_alignLeft="@+id/button1" 20 android:layout_alignRight="@+id/button1" 21 android:layout_below="@+id/button1" 22 android:layout_marginTop="131dp" 23 android:text="單車活動" /> 24 </RelativeLayout>

單車練習曲建置 6-3. Activity 註冊 AndroidManifest.xml 3 1 2

單車練習曲建置 6-3. Activity 註冊 新增一組 Activity

將新增的 Activity 選取對應的程式位置 單車練習曲建置 6-3. Activity 註冊 1 將新增的 Activity 選取對應的程式位置 ※此後新增一個 Activity,皆需要執行此註冊動作

單車練習曲建置 6-4.功能選單 select.java 1 2 3 4 5 6 7 8 9 Button friend; 10 import android.app.Activity; 2 import android.content.Intent; 3 import android.os.Bundle; 4 import android.view.View; 5 import android.view.View.OnClickListener; 6 import android.widget.Button; 7 8 public class select extends Activity { 9 Button friend; 10 Button activity; 11 打開 select.java

單車練習曲建置 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.select); 15 findView(); 16 //前置先與 Layout 元件作連結 17 setListener(); 18 //設置觸發事件 19 } 20 public void findView() { 21 friend = (Button) findViewById(R.id.button1); 22 activity = (Button) findViewById(R.id.button2); 23 24

單車練習曲建置 25 public void setListener(){ 26 activity.setOnClickListener(new OnClickListener() { 27 public void onClick(View v) { 28 Intent intent = new Intent(); 29 intent.setClass(select.this, activity.class); 30 startActivity(intent); 31 } 32 }); 33 //設置觸發點擊活動按鈕事件即轉跳到活動功能清單 34 friend.setOnClickListener(new OnClickListener() { 35 36 37 intent.setClass(select.this, friend_list.class);

單車練習曲建置 38 39 40 41 42 43 44 45 46 47 48 49 50 startActivity(intent); } 40 }); 41 42 //設置觸發點擊活動按鈕事件即轉跳到朋友清單 43 protected void onResume() { 44 super.onResume(); 45 Intent intent = new Intent(this,backgroundService.class); 46 startService(intent); 47 //啟動更新用戶位置的 Background Service 48 49 50

單車練習曲建置 6-5. Background Service Service Lifecycle Background Service與Activity兩者最大區別就是「Service完全沒有UI」,且擁有獨立的生命週期,如圖二所示。而Service 與App的Activity生命週期互不影響,Service 生命週期只繼承其中的onCreate()、onStart()、onDestroy(),一旦啟動,服務就會直接在背景執行,而除非重新開機或透過呼叫stopService()方法停止該服務,否則Android系統並不會自動銷毀該服務,而本章魔法地圖的Background Service 設計讓使用者一打開程式,就馬上執行Service,當偵測到位置改變時,手機馬上會上傳更新該用戶目前所在位置(當程式關閉還是會持續更新),進而達到魔法地圖可以觀察活動受邀好友的所在位置。 Service Lifecycle

單車練習曲建置 6-5. Background Service AndroidManifest.xml 3 1 2

單車練習曲建置 6-5. Background Service 新增一組 Service

將 Service 設定給 backgroundService 物件 單車練習曲建置 6-5. Background Service 1 將 Service 設定給 backgroundService 物件

打開 backgroundService.java 單車練習曲建置 6-5. Background Service backgroundService.java 1 import org.apache.http.HttpEntity; 2 import org.apache.http.HttpResponse; 3 import org.apache.http.client.HttpClient; 4 import org.apache.http.client.methods.HttpGet; 5 import org.apache.http.impl.client.DefaultHttpClient; 6 import org.apache.http.util.EntityUtils; 7 import android.app.Service; 8 import android.content.Context; 9 import android.content.Intent; 10 import android.location.Criteria; 11 import android.location.Location; 打開 backgroundService.java

單車練習曲建置 12 import android.location.LocationListener; 13 import android.location.LocationManager; 14 import android.os.Bundle; 15 import android.os.IBinder; 16 17 public class backgroundService extends Service { 18 private Location locationInfo; 19 public void onCreate() { 20 LocationManager locationManager = 21 (LocationManager) getSystemService(Context.LOCATION_SERVICE); 22 String bestProvider = locationManager.getBestProvider(new Criteria(), true); 23 //初始化 locationManager 並取得最佳定位提供者 24

單車練習曲建置 25 26 27 28 29 30 31 32 33 34 35 36 37 locationManager. requestLocationUpdates(bestProvider, 10000, 1, locationListener); 27 //定位更新(bestProvider ,時間間隔10000ms ,距離間隔1m ,監聽物件) 28 super.onCreate(); 29 } 30 31 public IBinder onBind(Intent arg0) { 32 return null; 33 34 35 private void updateLoaction() { 36 String url = value.service + "updateLocation.php?simid=" + value.simid 37 + "&lat=" + locationInfo.getLatitude() + "&lng="

單車練習曲建置 38 + locationInfo.getLongitude(); 39 HttpGet get = new HttpGet(url); 40 try { 41 HttpClient client = new DefaultHttpClient(); 42 HttpResponse response = client.execute(get); 43 HttpEntity resEntity = response.getEntity(); 44 String result = EntityUtils.toString(resEntity); 45 } catch (Exception e) { 46 } 47 48 49 private LocationListener locationListener = new LocationListener() { 50 public void onLocationChanged(Location location) {

單車練習曲建置 51 locationInfo = location; 52 if (location != null) { 53 Thread theard = new Thread() { 54 public void run() { 55 updateLoaction(); 56 /* 當觸發LocationChanged事件,即呼叫 updateLocation() 更新最新經緯度到 57 Server 上 */ 58 } 59 }; 60 theard.start(); 61 62 63

單車練習曲建置 64 public void onProviderDisabled(String arg0) { 65 } 66 67 public void onProviderEnabled(String arg0) { 68 69 70 public void onStatusChanged(String arg0, int arg1, Bundle arg2) { 71 72 }; 73 74 75 private void updateLoaction() { 76 String url = value.service + "updateLocation.php?simid="

單車練習曲建置 77 + value.simid + "&lat=" + locationInfo.getLatitude() 78 + "&lng=" + locationInfo.getLongitude(); 79 80 HttpGet get = new HttpGet(url); 81 try { 82 HttpClient client = new DefaultHttpClient(); 83 HttpResponse response = client.execute(get); 84 HttpEntity resEntity = response.getEntity(); 85 String result = EntityUtils.toString(resEntity); 86 } catch (Exception e) { 87 } 88 89

單車練習曲建置 7. 用戶清單功能描述 Android Web Service friend_list.java 4 Require 列出所有用戶清單,此區目前僅列出所有註冊用戶的名稱 simid name none Web Service JSON GET user.php 查詢出所有用戶的名稱清單 Response

單車練習曲建置 7-1. 查詢所有用戶資訊 Service user.php 1 2 3 4 5 6 7 8 9 10 11 include("../connect.php"); 2 $sql = "SELECT simid,name FROM user"; 3 $result = mysql_query($sql, $link) or die("oops"); 4 //查詢所有使用者 5 $data = array(); 6 while($row = mysql_fetch_array($result,MYSQL_ASSOC)){ 7 array_push($data,$row); 8 //將所有查詢出來的資料放入 $data 陣列當中 9 } 10 echo json_encode($data); 11 //透過 json 來制定格式傳遞資料

單車練習曲建置 7-2.用戶清單功能 Layout friend_list.xml 1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <ListView 7 android:id="@+id/listView1" 8 9 android:layout_height="wrap_content" > 10 </ListView> 11 </LinearLayout>

單車練習曲建置 7-3.用戶清單功能 friend_list.java 1 2 3 4 5 6 7 8 9 10 11 import org.apache.http.HttpEntity; 2 import org.apache.http.HttpResponse; 3 import org.apache.http.client.HttpClient; 4 import org.apache.http.client.methods.HttpGet; 5 import org.apache.http.impl.client.DefaultHttpClient; 6 import org.apache.http.util.EntityUtils; 7 import org.json.JSONArray; 8 import org.json.JSONException; 9 import org.json.JSONObject; 10 import android.app.Activity; 11 import android.os.Bundle; 打開 friend_list.java

單車練習曲建置 12 import android.os.Handler; 13 import android.os.Message; 14 import android.util.Log; 15 import android.widget.ArrayAdapter; 16 import android.widget.ListView; 17 18 public class friend_list extends Activity { 19 ListView listView; 20 21 protected void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.friend_list); 24 findView();

單車練習曲建置 25 26 27 28 29 30 31 32 33 34 35 36 37 //前置先與 Layout 元件作連結 FriendList fl = new FriendList(); 27 fl.start(); 28 //執行 fl 執行緒 來向 Service 請求所有使用者的資料 29 } 30 31 public void findView() { 32 listView = (ListView) findViewById(R.id.listView1); 33 34 35 class FriendList extends Thread { 36 public void run() { 37 super.run();

單車練習曲建置 38 try { 39 HttpClient client = new DefaultHttpClient(); 40 String url = value.service + "user.php"; 41 HttpGet get = new HttpGet(url); 42 HttpResponse response = client.execute(get); 43 HttpEntity resEntity = response.getEntity(); 44 String result = EntityUtils.toString(resEntity); 45 46 Bundle countBundle = new Bundle(); 47 countBundle.putString("list", result); 48 //打包朋友清單相關資料,並命名為 list 49 Message msg = new Message(); 50 msg.setData(countBundle);

單車練習曲建置 51 mHandler.sendMessage(msg); 52 //將打包資料方置放在 Message 物件當中,並傳送給 handler 53 } catch (Exception e) { 54 e.printStackTrace(); 55 } 56 57 58 59 private Handler mHandler = new Handler() { 60 public void handleMessage(Message msg) { 61 super.handleMessage(msg); 62 setList(msg.getData().getString("list")); 63 /*

單車練習曲建置 64 透過 handler 來請 main thread 處理 setList 65 sub thread 不能值接對 UI 作控制,必須透過 handler 來請主程序作 66 */ 67 } 68 }; 69 70 public void setList(String list) { 71 JSONArray json; 72 try { 73 json = new JSONArray(list); 74 String[] values = new String[json.length()]; 75 for (int i = 0; i < json.length(); i++) { 76 JSONObject jsonData = new JSONObject(json.get(i).toString());

單車練習曲建置 77 values[i] = jsonData.getString("name"); 78 } 79 listView.setAdapter(new ArrayAdapter<String>(this, 80 android.R.layout.simple_list_item_1, values)); 81 //將字串 list 回傳的 JSON 透過解析後存到 values 陣列並傳給 listView 作清單的顯示 82 } catch (JSONException e) { 83 e.printStackTrace(); 84 85 86 87 88 89

單車練習曲建置 8. 活動清單功能描述 Android Web Service activity.java 5 Require aid 建立活動 Require 列出所有活動清單,並增加一個建立活動的按鈕 aid title simid Web Service JSON GET activity.php 查詢出所有活動的名稱與活動編號 Response

單車練習曲建置 8-1. 參與活動清單 Service activity.php 1 2 3 4 5 6 7 8 9 10 11 if (isset($_GET['simid'])) { 2 $simid = mysql_real_escape_string($_GET['simid']); 3 //透過 GET 代入 simid (SIM Card ID) 參數 4 include("../connect.php"); 5 $sql = "SELECT title,c.aid FROM `join` c JOIN `activity` a on c.aid = a.aid 6 WHERE c.simid = '$simid'"; 7 $result = mysql_query($sql, $link) or die("oops"); 8 /* JOIN join 與 activity 兩張資料表, 9 並篩選出 $simid 用戶有參與的活動 title (活動名稱) 與 aid (活動編號) 10 */ 11 $data = array();

單車練習曲建置 12 while($row = mysql_fetch_array($result,MYSQL_ASSOC)){ 13 array_push($data,$row); 14 //將所有查詢出來的資料放入 $data 陣列當中 15 } 16 echo json_encode($data); 17 //透過 json 來制定格式傳遞資料 18 19 20 21 22 23 24

單車練習曲建置 8-2.活動清單功能 Layout add_activity.xml 1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <Button 8 android:id="@+id/button1" 9 10 android:layout_height="wrap_content" 11 android:text="建立活動" />

單車練習曲建置 12 <ListView 13 android:id="@+id/listView1" 14 android:layout_width="match_parent" 15 android:layout_height="wrap_content" > 16 </ListView> 17 18 </LinearLayout> 19 20 21 22 23 24

單車練習曲建置 8-3.活動清單功能 activity.java 1 2 3 4 5 6 7 8 9 10 11 import org.apache.http.HttpEntity; 2 import org.apache.http.HttpResponse; 3 import org.apache.http.client.HttpClient; 4 import org.apache.http.client.methods.HttpGet; 5 import org.apache.http.impl.client.DefaultHttpClient; 6 import org.apache.http.util.EntityUtils; 7 import org.json.JSONArray; 8 import org.json.JSONException; 9 import org.json.JSONObject; 10 import android.app.Activity; 11 import android.content.Intent; 打開 activity.java

單車練習曲建置 12 import android.os.Bundle; 13 import android.os.Handler; 14 import android.os.Message; 15 import android.util.Log; 16 import android.view.View; 17 import android.view.View.OnClickListener; 18 import android.widget.AdapterView; 19 import android.widget.ArrayAdapter; 20 import android.widget.Button; 21 import android.widget.ListView; 22 import android.widget.AdapterView.OnItemClickListener; 23 24

單車練習曲建置 25 public class activity extends Activity { 26 ListView listView; 27 Button button; 28 String actionList[]; 29 protected void onCreate(Bundle savedInstanceState) { 30 super.onCreate(savedInstanceState); 31 setContentView(R.layout.add_activity); 32 findView(); 33 //前置先與 Layout 元件作連結 34 setListener(); 35 //設置觸發事件 36 ActionList al = new ActionList(); 37 al.start();

單車練習曲建置 38 } 39 40 public void findView() { 41 listView = (ListView) findViewById(R.id.listView1); 42 button = (Button) findViewById(R.id.button1); 43 44 45 public void setListener(){ 46 button.setOnClickListener(new OnClickListener() { 47 public void onClick(View v) { 48 Intent intent = new Intent(); 49 intent.setClass(activity.this, activity_map.class); 50 startActivity(intent);

單車練習曲建置 51 52 53 54 55 56 57 58 59 60 61 62 63 //觸發按鈕點擊事件後,轉跳到新增活動地圖頁面 } 53 }); 54 55 listView.setOnItemClickListener(new OnItemClickListener() { 56 public void onItemClick(AdapterView<?> parent, View v, 57 int position, long id) { 58 Intent intent = new Intent(); 59 Bundle bundle = new Bundle(); 60 bundle.putString("aid", actionList[position]); 61 //預先設定傳遞打包資料 62 intent.putExtras(bundle); 63 intent.setClass(activity.this, Map.class);

單車練習曲建置 64 65 66 67 68 69 70 71 72 73 74 75 76 startActivity(intent); //設定當觸發活動清單項目,轉跳到活動地圖功能頁面 66 } 67 }); 68 69 70 class ActionList extends Thread { 71 public void run() { 72 super.run(); 73 try { 74 HttpClient client = new DefaultHttpClient(); 75 String url = value.service + "activity.php?simid=" 76 + value.simid;

單車練習曲建置 77 HttpGet get = new HttpGet(url); 78 HttpResponse response = client.execute(get); 79 HttpEntity resEntity = response.getEntity(); 80 String result = EntityUtils.toString(resEntity); 81 Bundle countBundle = new Bundle(); 82 countBundle.putString("list", result); 83 //打包活動清單相關資料,並命名為 list 84 Message msg = new Message(); 85 msg.setData(countBundle); 86 mHandler.sendMessage(msg); 87 } catch (Exception e) { 88 e.printStackTrace(); 89 }

單車練習曲建置 90 } 91 92 93 private Handler mHandler = new Handler() { 94 public void handleMessage(Message msg) { 95 super.handleMessage(msg); 96 setList(msg.getData().getString("list")); 97 //透過 handler 來呼叫 setList() 傳送清單內容與更新活動清單 98 99 }; 100 101 public void setList(String list) { 102 JSONArray json;

單車練習曲建置 103 try { 104 json = new JSONArray(list); 105 String[] values = new String[json.length()]; 106 actionList = new String[json.length()]; 107 108 for (int i = 0; i < json.length(); i++) { 109 JSONObject jsonData = new JSONObject(json.get(i).toString()); 110 values[i] = jsonData.getString("title"); 111 actionList[i] = jsonData.getString("aid"); 112 } 113 114 //Json 回傳 title(活動標題) 與 aid(活動ID) 的資料,分別使用陣列來承接 115

單車練習曲建置 116 listView.setAdapter(new ArrayAdapter<String>(this, 117 android.R.layout.simple_list_item_1, values)); 118 } catch (JSONException e) { 119 e.printStackTrace(); 120 } 121 122 123 124 125 126 127 128

單車練習曲建置 9. 建立活動功能描述 Android Web Service 6 7 activity_map.java activity_title.java Require 設定活動標題,並列出好友選單透過勾選方式來加入參與人,且透過選取地圖位置來設定活動位置 title direction master friend[simid] response aid Web Service JSON addActivity.php GET 建立一筆新活動,設定活動名稱與位置,並可記錄所有參與人 Response

單車練習曲建置 9-1. 參與活動清單 Service addActivity.php 1 2 3 4 5 6 7 8 9 10 11 if (isset($_GET['title']) 2     && isset($_GET['direction']) 3     && isset($_GET['friend']) 4     && isset($_GET['master']) ) { 5     $title = mysql_real_escape_string($_GET['title']); 6     $direction = mysql_real_escape_string($_GET['direction']); 7     $friend = mysql_real_escape_string($_GET['friend']); 8     $master = mysql_real_escape_string($_GET['master']); 9     //透過 GET 代入 title (活動名稱) direction (路徑) 10     //friend (參與人) master (創立活動者)參數 11   $addFriends = explode(',',$friend);

單車練習曲建置 12 13 14 15 16 17 18 19 20 21 22 23 24 //透過 explode 作字串的分割 include("../connect.php"); 14       $sql = "INSERT INTO activity(title,direction,master_simid) " 15              ."VALUES('$title','$direction','$master')"; 16       $result = mysql_query($sql, $link) or die("oops"); 17       //先建立出一筆新活動,並設定 title (活動名稱) direction (路徑) 18       $aid = mysql_insert_id(); 19       //因 aid 為自動編號,故需透過 mysql_insert_id 來取得產生之活動編號 20       for($i=0;$i<count($addFriends);$i++) 21       { 22         $sql = "INSERT INTO `join`(simid,aid) VALUES('$addFriends[$i]','$aid')"; 23         $result = mysql_query($sql, $link) or die("oops"); 24       //將所有參與人ID與對應活動編號一筆筆新增到 `join` 資料表當中

單車練習曲建置 25 26 27 28 29 30 31 32 33 34 35 36 37 } if($result) {       } 26   if($result) 27     { 28       $data['responese'] = 'success'; 29       $data['aid'] = $aid; 30       echo json_encode($data); 31     } 32 } 33 34 35 36 37

單車練習曲建置 9-2.活動地圖打點功能 Layout activity_map.xml 1 2 3 4 5 6 7 8 9 10 11 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context=".MainActivity" > 10 11 <fragment

單車練習曲建置 12 13 14 15 16 17 18 19 20 21 22 23 24 android:id="@+id/map" android:layout_width="match_parent" 14 android:layout_height="match_parent" 15 class="com.google.android.gms.maps.MapFragment" /> 16 <Button 17 android:id="@+id/next" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content" 20 android:layout_alignParentBottom="true" 21 android:layout_centerHorizontal="true" 22 android:layout_marginBottom="14dp" 23 android:text="下一頁" /> 24 </RelativeLayout>

單車練習曲建置 9-3.活動地圖打點功能 activity_map.java 打開 activity_map.java 1 import java.text.MessageFormat; 2 import org.apache.http.HttpResponse; 3 import org.apache.http.client.HttpClient; 4 import org.apache.http.client.methods.HttpGet; 5 import org.apache.http.impl.client.DefaultHttpClient; 6 import org.apache.http.util.EntityUtils; 7 import org.json.JSONArray; 8 import org.json.JSONObject; 9 import android.app.Activity; 10 import android.content.Context; 11 import android.content.Intent; 打開 activity_map.java

單車練習曲建置 12 import android.location.Criteria; 13 import android.location.Location; 14 import android.location.LocationListener; 15 import android.location.LocationManager; 16 import android.os.Bundle; 17 import android.os.Handler; 18 import android.os.Message; 19 import android.util.Log; 20 import android.view.View; 21 import android.view.View.OnClickListener; 22 import android.widget.Button; 23 import android.widget.Toast; 24 import com.google.android.gms.maps.CameraUpdateFactory;

單車練習曲建置 25 import com.google.android.gms.maps.GoogleMap; 26 import com.google.android.gms.maps.MapFragment; 27 import com.google.android.gms.maps.GoogleMap.OnMapClickListener; 28 import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener; 29 import com.google.android.gms.maps.model.BitmapDescriptorFactory; 30 import com.google.android.gms.maps.model.LatLng; 31 import com.google.android.gms.maps.model.Marker; 32 import com.google.android.gms.maps.model.MarkerOptions; 33 public class activity_map extends Activity implements OnMarkerClickListener, 34 OnMapClickListener { 35     Location location; 36     GoogleMap mMap; 37     LatLng latlng = new LatLng(22.764702, 120.371935);

單車練習曲建置 38 Button next; 39     String lat, lng; 40     Location locationInfo; 41     Marker MyLocation; 42     Marker DestinationLocation; 43     String startLocation; 44     String endLocation; 45     @Override 46     protected void onCreate(Bundle savedInstanceState) { 47         super.onCreate(savedInstanceState); 48         setContentView(R.layout.activity_map); 49         findView(); 50         // 前置先與 Layout 元件作連結

單車練習曲建置 51 52 53 54 55 56 57 58 59 60 61 62 63 setMap(); // 設置地圖         // 設置地圖 53         setListener(); 54         // 設置觸發事件 55         setLocation(); 56     } 57 58     public void findView() { 59         next = (Button) findViewById(R.id.next); 60         mMap = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)) 61                 .getMap(); 62 63

單車練習曲建置 64 65 66 67 68 69 70 71 72 73 74 75 76 public void setMap() {         mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15.0f)); 66         mMap.setOnMapClickListener(this); 67     } 68 69     public void setLocation() { 70         LocationManager locationManager = 71                 (LocationManager) getSystemService(Context.LOCATION_SERVICE); 72         String bestProvider = locationManager.getBestProvider(new Criteria(),true); 73         // 初始化 locationManager 並取得最佳定位提供者 74         locationManager.requestLocationUpdates(bestProvider, 10000, 1, locationListener); 75         // 定位更新(bestProvider ,時間間隔1000ms ,距離間隔1m ,監聽物件)          76 }

單車練習曲建置 77     public void setListener() { 78         next.setOnClickListener(new OnClickListener() { 79             @Override 80             public void onClick(View v) { 81                 // TODO Auto-generated method stub 82 if (MyLocation == null) { 83 Toast.makeText(activity_map.this, "請等待定位", 84 Toast.LENGTH_LONG).show(); 85 return; 86 } 87                 if (lat.length() == 0 && lng.length() == 0) { 88                      Toast.makeText(activity_map.this, "請點選活動位置", 89                       Toast.LENGTH_LONG).show();

單車練習曲建置 90                 } else { 91                     // 單車活動起始位置(手機定位位置) 92                     startLocation = MyLocation.getPosition().latitude + "," 93                             + MyLocation.getPosition().longitude; 94                     //單車活動目的地位置(透過打點方式選擇) 95 endLocation = DestinationLocation.getPosition().latitude 96  + "," + DestinationLocation.getPosition().longitude; 97                     Thread theard = new Thread() { 98                         public void run() { 99                             String DirectionContent = GetDirection(startLocation, endLocation); 100                             Bundle countBundle = new Bundle();        101                             Message msg = new Message(); 102                             msg.setData(countBundle);

單車練習曲建置 103                             mHandler.sendMessage(msg); 104                         } 105                     }; 106                     theard.start(); 107                 } 108             } 109         }); 110     } 111 112     private Handler mHandler = new Handler() { 113         public void handleMessage(Message msg) { 114             super.handleMessage(msg); 115             // 跳頁並夾帶路徑的值

單車練習曲建置 116             toActivity(msg.getData().getString("direction")); 117         } 118     }; 119 120     public void toActivity(String DirectionContent) { 121         Intent intent = new Intent(); 122         intent.setClass(activity_map.this, activity_title.class); 123         Bundle bundle = new Bundle(); 124         bundle.putString("direction", DirectionContent); 125         intent.putExtras(bundle); 126         startActivity(intent); 127         finish(); 128     }

單車練習曲建置 129     @Override 130     public boolean onMarkerClick(Marker marker) { 131         return false; 132     } 133 134 135     public void onMapClick(LatLng point) { 136         // TODO Auto-generated method stub 137         // 若是尚未標記打點(定單車活動位置)則建立新的標記點 138         if (DestinationLocation == null) { 139             MarkerOptions lonlng = new MarkerOptions().position(point).title( 140                     point.toString()); 141             DestinationLocation = mMap.addMarker(lonlng);

單車練習曲建置 142         } else 143 // 有標籤則移動 144         { 145             DestinationLocation.setPosition(point); 146         } 147         lat = point.latitude + ""; 148         lng = point.longitude + ""; 149     } 150     private LocationListener locationListener = new LocationListener() { 151         public void onLocationChanged(Location location) { 152             LatLng latLng1 = new LatLng(location.getLatitude(),location.getLongitude()); 153             if (MyLocation == null) { 154                 MarkerOptions lonlng = new MarkerOptions()

單車練習曲建置 155                         .position(latLng1) 156                         .title("My location") 157                         .icon(BitmapDescriptorFactory 158                                 .defaultMarker(BitmapDescriptorFactory.HUE_BLUE)); 159   MyLocation = mMap.addMarker(lonlng); 160 // 當前位置的定位標記 161             } else { 162                 MyLocation.setPosition(latLng1); 163              } 164   } 165         @Override 166         public void onProviderDisabled(String arg0) { 167              // TODO Auto-generated method stub

單車練習曲建置 169         } 170         @Override 171         public void onProviderEnabled(String arg0) { 172             // TODO Auto-generated method stub 173 174 175         public void onStatusChanged(String arg0, int arg1, Bundle arg2) { 176 177 178     }; 179   180     public String GetDirection(String startLocation, String endLocation) { 181 // 透過Google Directions 取得路徑規劃 (起始位置,終點位置)

單車練習曲建置 182         String mapAPI ="http://maps.google.com/maps/api/directions/json?" 183                 + "origin={0}&destination={1}&language=zh-TW&sensor=true"; 184         String url = MessageFormat.format(mapAPI, startLocation, endLocation); 185         HttpGet get = new HttpGet(url); 186         try { 187             HttpClient httpClient = new DefaultHttpClient(); 188             HttpResponse httpResponse = httpClient.execute(get); 189             if (httpResponse.getStatusLine().getStatusCode() == 200) { 190                 String strResult = EntityUtils.toString(httpResponse.getEntity()); 191                 JSONObject jsonObject = new JSONObject(strResult); 192                 JSONArray routeObject = jsonObject.getJSONArray("routes"); 193                String polyline = routeObject.getJSONObject(0) 194                 

單車練習曲建置 195                         .getJSONObject("overview_polyline").getString("points"); 196                 return polyline; 197         } catch (Exception e) { 198             Log.e("map", "MapRoute:" + e.toString()); 199         } 200         return null; 201         // return _points; 202     } 203 } 204 205 206 207

單車練習曲建置 9-4.活動新增功能 Layout activity_title.xml 1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <Button 8 android:id="@+id/button1" 9 10 android:layout_height="wrap_content" 11 android:layout_alignParentBottom="true"

單車練習曲建置 12 android:layout_alignParentLeft="true" 13 android:layout_alignParentRight="true" 14 android:text="下一頁" /> 15 16 <EditText 17 android:id="@+id/editText1" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content" 20 android:layout_alignParentTop="true" 21 android:layout_centerHorizontal="true" 22 android:ems="10" 23 android:gravity="center" 24 android:text="活動名稱" >

單車練習曲建置 25 26 27 28 29 30 31 32 33 34 35 36 37 <requestFocus /> </EditText> 27 28 <ListView 29 android:id="@+id/listView1" 30 android:layout_width="match_parent" 31 android:layout_height="wrap_content" 32 android:layout_above="@+id/button1" 33 android:layout_alignParentLeft="true" 34 android:layout_below="@+id/editText1" > 35 </ListView> 36 </RelativeLayout> 37

打開 activity_title.java 單車練習曲建置 9-5.活動新增功能 activity_title.java import java.net.URLEncoder; 1 import java.text.MessageFormat; 2 import java.util.ArrayList; 3 import org.apache.http.HttpEntity; 4 import org.apache.http.HttpResponse; 5 import org.apache.http.client.HttpClient; 6 import org.apache.http.client.methods.HttpGet; 7 import org.apache.http.impl.client.DefaultHttpClient; 8 import org.apache.http.util.EntityUtils; 9 import org.json.JSONArray; 10 import org.json.JSONException; 11 import org.json.JSONObject; 打開 activity_title.java

單車練習曲建置 12 import android.app.Activity; 13 import android.content.Context; 14 import android.content.Intent; 15 import android.os.Bundle; 16 import android.os.Handler; 17 import android.os.Message; 18 import android.telephony.TelephonyManager; 19 import android.util.Log; 20 import android.view.View; 21 import android.view.View.OnClickListener; 22 import android.widget.AdapterView; 23 import android.widget.AdapterView.OnItemClickListener; 24 import android.widget.ArrayAdapter;

單車練習曲建置 25 import android.widget.Button; 26 import android.widget.EditText; 27 import android.widget.ListView; 28 29 public class activity_title extends Activity { 30     EditText editText; 31     Button button; 32 ListView listView; 33     ArrayList checkedList; 34     String DirectionContent; 35     String[] simidList; 36 37

單車練習曲建置 38     @Override 39     protected void onCreate(Bundle savedInstanceState) { 40         super.onCreate(savedInstanceState); 41         setContentView(R.layout.activity_title); 42         getValue(); 43         // 取得前頁 Intent 到此頁地圖標記位置資訊 44         findView(); 45         // 前置先與 Layout 元件作連結 46         setListener(); 47         // 設置觸發按鈕事件 48         FriendList fl = new FriendList(); 49         fl.start(); 50         // 執行FriendList執行序

單車練習曲建置 51     } 52 53     public void getValue() { 54         Bundle bundle = new Bundle(); 55         bundle = this.getIntent().getExtras(); 56    DirectionContent = bundle.getString("direction");       57         // 取出路徑規劃編碼 58     }   59 60     public void findView() { 61         listView = (ListView) findViewById(R.id.listView1); 62         button = (Button) findViewById(R.id.button1); 63         editText = (EditText) findViewById(R.id.editText1);

單車練習曲建置 64 65 66 public void setListener() { 67 68 69 70 71 72 73 74 checkedList = new ArrayList(); 65 } 66 67 public void setListener() { 68         button.setOnClickListener(new OnClickListener() { 69             @Override 70             public void onClick(View v) { 71                 AddAction AA = new AddAction(); 72                 AA.start(); 73             } 74         }); 75         // 設定觸發點擊事件 "下一頁" 的按鈕,會執行 AddAction Thread 76         

單車練習曲建置 77         listView.setOnItemClickListener(new OnItemClickListener() { 78             public void onItemClick(AdapterView parent, View v, 79                     int position, long id) { 80                 // Log.d("test","position:"+position+""); 81                 if (listView.getCheckedItemPositions().get(position)) { 82                     checkedList.add(position); 83                     // Log.d("test", "checkList:"+checkedList.toString()); 84                 } else { 85                     checkedList.remove(new Integer(position)); 86                     // Log.d("checkList", checkedList.toString()); 87                 } 88             } 89         });

單車練習曲建置 90 /* 設定觸發點擊事件好友清單的項目(Item) 91  *    會加入參與人陣列(checkedList) 92         * 打勾則加入清單資料,取消打勾則移除陣列清單資料 93   */ 94 95         editText.setOnClickListener(new OnClickListener() { 96             @Override 97             public void onClick(View v) { 98                 editText.setText(""); 99             } 100         }); 101         // 設定觸發點擊文字輸入(Title 文字欄位),即清空文字內容(預設為"活動名稱") 102     }

單車練習曲建置 103     // 取得好友清單 104     class FriendList extends Thread { 105   106         @Override 107         public void run() { 108             // TODO Auto-generated method stub 109             super.run(); 110             try { 111                 HttpClient client = new DefaultHttpClient(); 112                 String url = value.service + "user.php"; 113                 HttpGet get = new HttpGet(url); 114                 HttpResponse response = client.execute(get); 115

單車練習曲建置 116                 HttpEntity resEntity = response.getEntity(); 117                 String result = EntityUtils.toString(resEntity); 118                 // Log.d("result", result); 119                 Bundle countBundle = new Bundle(); 120                 countBundle.putString("list", result); 121                 Message msg = new Message(); 122                 msg.setData(countBundle); 123                 mHandler.sendMessage(msg); 124             } catch (Exception e) { 125                 e.printStackTrace(); 126             } 127         } 128

單車練習曲建置 129     } 130   131     private Handler mHandler = new Handler() { 132         public void handleMessage(Message msg) { 133             super.handleMessage(msg); 134             setList(msg.getData().getString("list")); 135         } 136     }; 137 138     public void setList(String list) { 139         JSONArray json; 140         try { 141

單車練習曲建置 142             json = new JSONArray(list); 143             String[] values = new String[json.length()]; 144             simidList = new String[json.length()]; 145             for (int i = 0; i < json.length(); i++) { 146                 JSONObject jsonData = new JSONObject(json.get(i).toString()); 147                 values[i] = jsonData.getString("name"); 148                 simidList[i] = jsonData.getString("simid"); 149             } 150             listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 151             // 設定ListView 為 複選模式 152             listView.setAdapter(new ArrayAdapter(this, 153                     android.R.layout.simple_list_item_multiple_choice, values)); 154

單車練習曲建置 155         } catch (JSONException e) { 156             // TODO Auto-generated catch block 157             e.printStackTrace(); 158         } 159   160     } 161 162      163     class AddAction extends Thread { 164  // 建立活動 165         @Override 166         public void run() { 167

單車練習曲建置 169             // TODO Auto-generated method stub 170             super.run(); 171             String list = ""; 172             for (int i = 0; i < checkedList.size(); i++) { 173                 if (checkedList.size() - 1 == i) { 174                     list += simidList[checkedList.get(i)]; 175                 } else { 176                     list += simidList[checkedList.get(i)] + ","; 177                 } 178                 // Log.d("test", "list:"+list); 179             } 180             try { 181

單車練習曲建置 182                 // 新增活動,並且記錄創辦活動者 183                 String mapAPI = value.service 184                     + "addActivity.php?title={0}" 185                     + "&direction={1}&friend={2}&master={3}"; 186                 String url = MessageFormat.format(mapAPI, editText.getText() 187                         .toString(), URLEncoder.encode(DirectionContent, 188                         "UTF-8"), list, value.simid); 189 /* 透過 Http Get 傳送到Web Service 190               (1:活動名稱,2:路徑編碼,3:邀請人[],4:領隊Simid)  */ 191   HttpClient client = new DefaultHttpClient(); 192                 HttpGet get = new HttpGet(url); 193                 HttpResponse response = client.execute(get); 194

單車練習曲建置 195                 HttpEntity resEntity = response.getEntity(); 196                 String result = EntityUtils.toString(resEntity); 197                 // Log.d("test", result); 198                 Bundle countBundle = new Bundle(); 199                 countBundle.putString("list", result); 200                 // Log.d("test", "result:"+result); 201                 Message msg = new Message(); 202                 msg.setData(countBundle); 203                 mHandler2.sendMessage(msg); 204             } catch (Exception e) { 205                 e.printStackTrace(); 206             } 207

單車練習曲建置 208         } 209     } 210   211     private Handler mHandler2 = new Handler() { 212         public void handleMessage(Message msg) { 213             super.handleMessage(msg); 214             changePage(msg.getData().getString("list")); 215 216     }; 217 218     public void changePage(String list) { 219 220

單車練習曲建置 221         try { 222             JSONObject jsonObj = new JSONObject(list); 223             String aid = jsonObj.getString("aid"); 224             Intent intent = new Intent(); 225             Bundle bundle = new Bundle(); 226             // Log.d("test",aid); 227             bundle.putString("aid", aid); 228   229             intent.putExtras(bundle); 230             intent.setClass(activity_title.this, Map.class); 231             startActivity(intent); 232             finish(); 233

單車練習曲建置 234 235 236 237 238 /* 完成頁面轉跳後,即關閉此Activity             目的在於不讓使用者返回上一頁(新增活動功能頁面) */ 236         } catch (JSONException e) { 237             // TODO Auto-generated catch block 238             e.printStackTrace(); 239         } 240     } 241  } 242 243 244 245 246

單車練習曲建置 10. 單車練習曲功能描述 Android Web Service 9 map.java Require name lat 在地圖上顯示活動位置與所有參與人目前位置資訊 name lat lng aid simid Web Service GET JSON joinUser.php 查詢此活動以及所有參與人的相關位置資訊 Response

單車練習曲建置 10-1. 單車活動參與人資訊 Service joinUser.php 1 2 3 4 5 6 7 8 9 10 11 if (isset($_GET['aid'])&&isset($_GET['simid'])) { 2     $aid = mysql_real_escape_string($_GET['aid']); 3     $simid = mysql_real_escape_string($_GET['simid']); 4     //透過 GET 代入 aid (活動編號) simid (手機編號) 參數 5     include("../connect.php"); 6     $sql = "SELECT * FROM activity WHERE aid = '$aid'"; 7     $result = mysql_query($sql, $link) or die("oops1"); 8     $row = mysql_fetch_array($result,MYSQL_ASSOC); 9     $activity['title'] = $row['title']; 10 $activity['direction'] = $row['direction']; 11     $master_simid = $row['master_simid'];

單車練習曲建置 12 //查詢活動的相關資訊,活動名稱(title),活動路徑(dirction),領隊(master_simid) 13     $sql = "SELECT u.simid,name,lat,lng FROM `join` c JOIN `user` u " 14             ."on u.simid = c.simid WHERE c.aid = '$aid'"; 15     $result = mysql_query($sql, $link) or die(mysql_error()); 16     /* JOIN join 與 user 兩張資料表, 17         並篩選出所有參與 $aid 活動中參與人的 name (名稱) 與 lat, lng (經緯度) 18     */ 19 $data = array(); 20     while($row = mysql_fetch_array($result,MYSQL_ASSOC)){ 21         if($row['simid']==$master_simid) 22         { 23             $activity['master_simid']=$row['simid']; 24             $activity['master_name']=$row['name'];

單車練習曲建置 25             $activity['master_lat']=$row['lat']; 26             $activity['master_lng']=$row['lng']; 27         }else if($row['simid']==$simid) 28         { 29             $activity['user_simid']=$row['simid']; 30             $activity['user_name']=$row['name']; 31     $activity['user_lat']=$row['lat']; 32 $activity['user_lng']=$row['lng']; 33         }else 34 35             array_push($data,$row); 36         } 37     //將所有查詢出來的資料放入 $data 陣列當中

單車練習曲建置 25     } 26   27     $activity['list']=$data; 28 29     echo json_encode($activity); 30 } 31 32 33 34 35 36 37

單車練習曲建置 10-2.單車練習曲功能 Layout map.xml 1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="utf-8"?> 2 <fragment xmlns:android="http://schemas.android.com/apk/res/android" 3 android:id="@+id/map" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 class="com.google.android.gms.maps.MapFragment"/> 7 8 9 10 11

單車練習曲建置 10-3.單車練習曲功能 map.java 打開 map.java 1 import java.util.ArrayList; 2 import java.util.HashMap; 3 import org.apache.http.HttpEntity; 4 import org.apache.http.HttpResponse; 5 import org.apache.http.client.HttpClient; 6 import org.apache.http.client.methods.HttpGet; 7 import org.apache.http.impl.client.DefaultHttpClient; 8 import org.apache.http.util.EntityUtils; 9 import org.json.JSONArray; 10 import org.json.JSONException; 11 import org.json.JSONObject; 打開 map.java

單車練習曲建置 13 import android.app.Activity; 14 import android.content.Context; 15 import android.graphics.Color; 16 import android.location.Location; 17 import android.os.Bundle; 18 import android.os.Handler; 19 import android.os.Message; 20 import android.telephony.TelephonyManager; 21 import android.util.Log; 22 import com.google.android.gms.maps.CameraUpdateFactory; 23 import com.google.android.gms.maps.GoogleMap; 24 import com.google.android.gms.maps.MapFragment;

單車練習曲建置 25 import com.google.android.gms.maps.model.BitmapDescriptorFactory; 26 import com.google.android.gms.maps.model.CameraPosition; 27 import com.google.android.gms.maps.model.CircleOptions; 28 import com.google.android.gms.maps.model.LatLng; 29 import com.google.android.gms.maps.model.Marker; 30 import com.google.android.gms.maps.model.MarkerOptions; 31 import com.google.android.gms.maps.model.PolylineOptions; 32   33 public class Map extends Activity { 34     Location location; 35     GoogleMap mMap; 36     LatLng latlng = new LatLng(22.764702, 120.371935);

單車練習曲建置 37 String aid = ""; 38 boolean checkDFirst= true; 39     private Handler handler = new Handler(); 40     ArrayList ALDirection; 41     HashMap<String,Marker> Member=new HashMap<String,Marker>(); 42     double setDistance=5; 43     //設定隊員與領隊相差多少距離(公尺)提醒 44 45     @Override 46     protected void onCreate(Bundle savedInstanceState) { 47         super.onCreate(savedInstanceState); 48

單車練習曲建置 49 setContentView(R.layout.map); 50 findView(); 51 52         getValue(); 53         //取得前頁 Intent 的相關參數 54         setMap(); 55         //設置地圖 56         simid(); 57         //取得手機編號 58         SetMarker Stm = new SetMarker(); 59         Stm.start(); 60         //啟用 Thread 來執行 Service

單車練習曲建置 61 } 62 63 public void findView() { 64     } 62      63     public void findView() { 64         mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)) 65                 .getMap(); 66 67 68     public void getValue() { 69         Bundle bundle = new Bundle(); 70         bundle = this.getIntent().getExtras(); 71         aid = bundle.getString("aid"); 72         //設定活動地圖標記位置經緯度

單車練習曲建置 73 } 74 public void setMap(){ 75         mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, 15.0f)); 76         //設置地圖 Camera 移動位置與縮放大小 77     } 78 79     public void simid() { 80         TelephonyManager manager = 81                 (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 82         value.simid = manager.getDeviceId(); 83         //透過 TelephonyManager 取得 SimCard ID,存放到 value.simid 84

單車練習曲建置 85 class SetMarker extends Thread { 86 @Override 87         public void run() { 88             // TODO Auto-generated method stub 89             super.run(); 90             try { 91                 while(true) 92                 { 93                     HttpClient client = new DefaultHttpClient(); 94                     String url = value.service + "joinUser.php?aid=" 95                                     + aid + "&simid=" + value.simid; 96                     HttpGet get = new HttpGet(url);

單車練習曲建置 97 HttpResponse response = client.execute(get); 98                     HttpEntity resEntity = response.getEntity(); 99                     String result = EntityUtils.toString(resEntity); 100                     //Log.d("test", "result"+result); 101                     Bundle countBundle = new Bundle(); 102                     countBundle.putString("list", result); 103                     Message msg = new Message(); 104                     msg.setData(countBundle); 105                     //將 Service 資料回傳並存放在 Message 當中 106                     mHandler.sendMessage(msg); 107                     //透過 Handler 來傳遞資料並更新UI(地圖標記) 108                     Thread.sleep(5000);

單車練習曲建置 private Handler mHandler = new Handler() { 109 } 110                 } 110             } catch (Exception e) { 111                 e.printStackTrace(); 112             } 113         } 114     } 115 116     private Handler mHandler = new Handler() { 117         public void handleMessage(Message msg) { 118             super.handleMessage(msg); 119             try { 120                 String JsonStr=msg.getData().getString("list");

單車練習曲建置 121 Log.i("Json", JsonStr); 122                 JSONObject AllObject=new JSONObject(JsonStr); 123                 //路徑規劃(繪製路徑),僅執行一次 124                 if(checkDFirst) 125                 { 126                     String Direction=AllObject.getString("direction"); 127                     ALDirection=decodePoly(Direction); 128                     drawPath(ALDirection); 129                     checkDFirst=false; 130                 }   131                   double[] master_location=addMasterMO(AllObject);             132   //設定領隊標記,並且回傳座標

單車練習曲建置 } 133 if(!AllObject.isNull("user_name")) 134 { 135                 { 135                     addUserMO(AllObject,master_location); 136 //若使用者非領隊則新增活動參與人標記 137                 } 138                 JSONArray jsonData = AllObject.getJSONArray("list"); 139                 JSONObject jsonObject; 140 //取出其他活動參與人資訊 141     142                 for (int i = 0; i < jsonData.length(); i++) { 143                     jsonObject = jsonData.getJSONObject(i); 144                     String simid=jsonObject.getString("simid");

單車練習曲建置 146 double lat = Double.parseDouble(jsonObject 147                             .getString("lat")); 148                     double lng = Double.parseDouble(jsonObject 149                             .getString("lng")); 150                     String title = jsonObject.getString("name"); 151                     double distance=getDistance(master_location[0] 152                                         ,master_location[1],lat,lng); 153                      //計算領隊與所有參與人位置之間的距離 154                     LatLng latLng = new LatLng(lat, lng); 155                     setMarker(simid, latLng, title, distance 156                             , BitmapDescriptorFactory.HUE_VIOLET 157                             , BitmapDescriptorFactory.HUE_AZURE);

單車練習曲建置 } 158 159 //設定標記屬性(超出位置呈現紫色,未超出呈現藍色) 160                 } 159 //設定標記屬性(超出位置呈現紫色,未超出呈現藍色) 160                 CameraPosition cameraPosition = new CameraPosition.Builder() 161                .target(Member.get(value.simid).getPosition()) 162                .zoom(19) 163                 .build(); 164 //鏡頭移到定位地點 165                 mMap.animateCamera(CameraUpdateFactory 166                                         .newCameraPosition(cameraPosition)); 167             } catch (JSONException e) { 168                 e.printStackTrace(); 169             }

單車練習曲建置 170 } 171 }; 172 173 //領隊標記屬性設定 174         } 171     }; 172      173     //領隊標記屬性設定 174     private double[] addMasterMO(JSONObject AllObject) 175             throws NumberFormatException, JSONException 176     { 177         String simid = AllObject.getString("master_simid"); 178         double lat = Double.parseDouble(AllObject 179                 .getString("master_lat")); 180         double lng = Double.parseDouble(AllObject 181                 .getString("master_lng"));

單車練習曲建置 182 String title = AllObject.getString("master_name"); 183         //解析並取出領隊經緯度與名稱 184         LatLng latLng = new LatLng(lat, lng); 185         Marker marker=Member.get(simid); 186 187         if(marker==null) 188         { 189 //如果沒有這個標記則建立一個新的橘色標記 190             MarkerOptions markerOptions = new MarkerOptions(); 191             markerOptions.position(latLng); 192             markerOptions.title(title); 193             markerOptions

單車練習曲建置 194 .icon(BitmapDescriptorFactory 195                         .defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)); 196             Member.put(simid,mMap.addMarker(markerOptions)); 197         }else 198         { 199             marker.setPosition(latLng); 200             marker.setTitle(title); 201         } 202         return new double[]{lat,lng}; 203     } 204 205

單車練習曲建置 206     //自己標記屬性設定 207     private void addUserMO(JSONObject AllObject,double[] master_location) 208             throws NumberFormatException, JSONException 209     { 210         String simid=AllObject.getString("user_simid"); 211         double lat = Double.parseDouble(AllObject 212                 .getString("user_lat")); 213         double lng = Double.parseDouble(AllObject 214                 .getString("user_lng")); 215         String title = AllObject.getString("user_name"); 216         double distance=getDistance(master_location[0],master_location[1],lat,lng); 217         //計算領隊與自己當前位置之間的距離

單車練習曲建置 218 LatLng latLng = new LatLng(lat, lng); 219 setMarker(simid 220                 ,latLng 221                 ,title 222                 ,distance 223                 ,BitmapDescriptorFactory.HUE_VIOLET 224                 ,BitmapDescriptorFactory.HUE_YELLOW); 225     } 226    //設定標記屬性(超出位置呈現紫色,未超出呈現黃色) 227     private void setMarker(String simid 228                             ,LatLng latLng 229                             ,String title

單車練習曲建置 230 ,double distance 231 ,float exceed 232 ,float notExceed) 233     { 234         Marker marker=Member.get(simid); 235         if(marker==null) 236         { 237 //如果沒有這個標籤則建立新標記 238             MarkerOptions markerOptions = new MarkerOptions(); 239             markerOptions.position(latLng); 240             markerOptions.title(title); 241 //超出距離切換座標顏色

單車練習曲建置 242 if(setDistance < distance) 243 { 244             { 244                 markerOptions.icon(BitmapDescriptorFactory.defaultMarker(exceed)); 245 //兩點間超出距離設定標記顏色(exceed) 246             }else 247 248                 markerOptions.icon(BitmapDescriptorFactory.defaultMarker(notExceed)); 249 //兩點間未超出距離設定標記顏色(notExceed) 250             } 251             Member.put(simid,mMap.addMarker(markerOptions)); 252         }else 253         {

單車練習曲建置 254 marker.setPosition(latLng); 255 marker.setTitle(title); 256             if(setDistance<distance) 257             { 258                 marker.setIcon(BitmapDescriptorFactory.defaultMarker(exceed)); 259 //兩點間超出距離設定標記顏色(exceed) 260             }else 261 262                 marker.setIcon(BitmapDescriptorFactory.defaultMarker(notExceed)); 263 //兩點間未超出距離設定標記顏色(notExceed) 264             } 265         }

單車練習曲建置 266     } 267 268     public double getDistance(double lat1, double lon1, double lat2, double lon2) { 269         float[] data = new float[1]; 270         Location.distanceBetween(lat1, lon1, lat2, lon2, data); 271 //計算兩座標之間的距離 272         return data[0]; 273 274     //路線規劃繪圖 275     private void drawPath(final ArrayList points) 276     { 277         Runnable r1=new Runnable() {

單車練習曲建置 278 @Override 279 public void run() { 280                 // TODO Auto-generated method stub 281                 mMap.addPolyline(new PolylineOptions(). 282                            addAll(points). 283                            width(5). 284                            color(Color.BLUE)); 285 286                   for(int i=0;i<points.size();i++) 287                   { 288                       mMap.addCircle(new CircleOptions(). 289                               center(points.get(i)).

單車練習曲建置 290 radius(5). 291 strokeWidth(5). 292                               strokeColor(Color.RED)); 293                   } 294                   mMap.addMarker(new MarkerOptions() 295                         .position(points.get(0)) 296                         .title("我是起點") 297                         .snippet("我是起點")); 298 299                         .position(points.get(points.size()-1)) 300                         .title("我是終點") 301                         .snippet("我是終點"));

單車練習曲建置 } 303 304 }; 305 handler.post(r1); 306 } 307 308 /** 309             } 304         }; 305         handler.post(r1); 306     } 307      308     /** 309      * 解碼折線點的方法 310      * */ 311     private ArrayList decodePoly(String encoded) { 312         ArrayList poly = new ArrayList(); 313         int index = 0, len = encoded.length(); 314        int lat = 0, lng = 0;

單車練習曲建置 315 while (index < len) { 316 int b, shift = 0, result = 0; 317             do { 318                 b = encoded.charAt(index++) - 63; 319                 result |= (b & 0x1f) << shift; 320                 shift += 5; 321             } while (b >= 0x20); 322             int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 323             lat += dlat; 324             shift = 0; 325             result = 0; 326  

單車練習曲建置 328 do { 329 b = encoded.charAt(index++) - 63; 330                 result |= (b & 0x1f) << shift; 331                 shift += 5; 332             } while (b >= 0x20); 333             int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 334             lng += dlng; 335   336             LatLng p = new LatLng((((double) lat / 1E5)), 337                     (((double) lng / 1E5))); 338             poly.add(p); 339         }

單車練習曲建置 340 return poly; 341 } 342 } 343 344 345 346 347 348 349 350     } 342 } 343 344 345 346 347 348 349 350 351