星期三, 10月 09, 2013

Code Lab - RESTful App on Android : A POI Map

此Android程式練習是為成大資工系-電腦通訊網路課程 所設計的一個Code Lab,目的在介紹REST架構的運作原理,以及在Android上面如何實作包含Google Map、Http Request、AsyncTask及UI Adapter應用。

此App運用DEH API來開發一個簡易的LBS服務,查詢地圖中心附近2公里內所包含的景點有哪些。

課程時間:3小時
投影片下載
在Google Play下載:
Get it on Google Play


Check Point 0 : Android 環境設定

安裝設定Android開發環境,以繼續接下來的練習

Step 1 : 下載並安裝Android ADT Bundle 並安裝Android SDK

Step 2 : 下載RESTDemo Project ,並進行解壓縮

  • URL:  下載
  • Do not publish this code to Google Play !!

Step 3 : 在新的Workspace 中,匯入RESTDemo Project

  • File > Import > Android > Existing Android Code into Workspace
  • 選擇Project路徑
  • 按下Select All 按鈕
  • 勾選 Copy project into workspace

Step 4 : 設定Project Build Target為Google APIs Level 18

  • Project上按右鍵 > Properties > Android > Project Build Target > Google APIs Level 18

Step 5 : 註冊下載Genymotion Android 模擬器 / 或使用Android 手機

Step 6 :建立模擬器

  • 執行Genymotion並建立一個Galaxy Nexus with Google App API17
  • 下載完成後依指示設定Android SDK路徑
  • 在手機設定中開啟Setting > Developer options > Usb debugging (若沒有Developer options,先到About  phone裡面連點build number)

Step 7 :嘗試在模擬器上執行專案
    *如果有任何錯誤,請坐下列檢查

    • ADT > Project > clean > clean all
    • Project右鍵 > property > Android > 檢查Build Target 及 Library

    Check Point 1 : Google Map API 環境

    Step 1 : 下載Google Play Service SDK 並引用之 (此步驟已經完成)

    • Window > Android SDK Manager >Extras > Google Play Service 勾選並下載
    • File > Import >  [sdk path]/extras/google/google play services/libproject/google_play_service_lib
    • Project name 右鍵 > Properties > Android > Library > Add > google-play-service_lib

    Step 2 : 找到你的Debug Key SHA1指紋碼

    • ADT(Window) > Preferences> Android > build > SHA1 fingerprint

    Step 3 : Google Console上設定Project

    Step 4 : 將Step 3取得的API Key填到AndroidManifest.xml中,之內


    android:name="com.google.android.maps.v2.API_KEY"
    android:value="AIzaSyAjP-Km7aFTWCRhvCTuuwiEf5NYIFw0EGQ" />

    Step 5 : 在虛擬機器上執行Project


    Check Point 2 : Send HTTP Request


    • 在MainActivity.doDataSearch()中置入送出Http request的程式碼,並以Log.i()來觀察取得的內容 (Window > showview > other > Android > Logcat)
    private void doDataSearch() {
     try {
      String result = sentHttpRequest(API_GET_NEARBY_POI + "?"+ "lat=" + defaultLocation.latitude + "&lng=" + defaultLocation.longitude+ "&dist=2000");
      Log.i("RESTDemo", result);
     } catch (Exception e) {   
      e.printStackTrace();
     } 
    }



    Check Point 3 : Send HTTP Request with AsyncTask

    • 在doDataSearch()中將Http request的程式碼換置為
    private void doDataSearch() { 
     new DataSearchAsyncTask().execute();
    }
    • 將原本在doDataSearch()中Http Request的程式碼,移至DataSearchAsyncTask.doInBackground當中
    @Override
    protected ArrayList doInBackground(Void... params) {
     ArrayList list = new ArrayList();
     try {    
      String result = sentHttpRequest(API_GET_NEARBY_POI + "?"+ "lat=" + center.latitude + "&lng=" + center.longitude+ "&dist=2000");
    
     } catch (Exception e) {
      e.printStackTrace();
     }
     return null;
    }

      Check Point 4 : Parse result and fill content to the ListView

      • 將http取得的內容,使用JSONObject和JSONArray來儲存,在DataSearchTask. doInBackground()當中加入下列內容進行解析
      JSONObject jsonObject = new JSONObject(result);
      JSONArray array = jsonObject.getJSONArray("results");
      for (int i = 0; i < array.length(); i++) {
       JSONObject poiObject = array.getJSONObject(i);
       Poi poi = new Poi();
              poi.setDescript(poiObject.getString("POI_description"));
       poi.setName(poiObject.getString("POI_title"));
       Double lat = Double.parseDouble(poiObject.getString("latitude"));
       Double lng = Double.parseDouble(poiObject.getString("longitude"));
       poi.setLatlng(new LatLng(lat, lng));
       list.add(poi);
      }
      • 在DataSearchTask.onPostExecute()當中,更新ListView內容
      if (MainActivity.this != null) {
       vRefreshBtn.setVisible(true);
              vDrawerLayout.openDrawer(vDrawerList);
       mPois = pois;
       if (mAdapter == null) {
        mAdapter = new PoiListAdapter();
                      vDrawerList.setAdapter(mAdapter);
       } else {
        mAdapter.notifyDataSetChanged();
       }
      }

      Check Point 5 : Shows POIs on the map 

      • 在initView()處,將ListView 加入回呼函數,處理當列表中某POI被選擇後的動作
      vDrawerList.setOnItemClickListener(new DrawerItemClickListener());
      • 建立OnItemClickListener類別接收POI被選擇的事件
      
      
      
      
      
      
      private class DrawerItemClickListener implements ListView.OnItemClickListener {
       @Override
       public void onItemClick(AdapterView parent, View view, int position, long id) {
        selectItem(position);
             }
      }
      
      private void selectItem(int position) {
       LatLng latLng = Pois.get(position).getLatlng();
       String title = mPois.get(position).getName();
       String desc = Pois.get(position).getDescript();
      
       vMap.clear();
       vMap.addMarker(new  MarkerOptions().position(latLng).title(title)    .snippet(desc));
      
       vMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18));
       vDrawerLayout.closeDrawers();
      
      }
      張貼留言