第三章 SaysApp 的設計與實現
3.3. 使用者端
3.3.3. SaysApp 的程式設計
SaysApp 會用到的 Class 和 Interface,在 Java 程式碼的最前面用 import 宣 告如下:
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.google.android.maps.GeoPoint;
26
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.OverlayItem;
宣告 SaysApp 程式繼承 MapActivity 類別,再在程式中宣告發言按鈕、名 稱輸入框、訊息輸入框、地圖、地圖控制器、自己地理位置的圖層、標記資訊 的圖層、字串陣列等物件。
public class SaysApp extends MapActivity { private Button sayButton;
private EditText nameET;
private EditText messageET;
private MapView mView;
private MapController mControl;
private MyLocationOverlay mlOverlay;
private MarkerOverlay saysoverlay;
private String[] stringArray;
27
當 SaysApp 程式開始執行的時候,先要設定程式所使用的 ContentView(介 面),然後用 findViews()方法設定介面中的元件與程式中的物件的對應,最後 用 initMapView()方法起始地圖。
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
initMapView();
定義 findViews()方法:設定介面中的 4 個元件與程式中的 4 個物件的對 應。
private void findViews() {
sayButton = (Button) findViewById(R.id.sayButton);
nameET = (EditText) findViewById(R.id.nameET);
messageET = (EditText) findViewById(R.id.messageET);
mView = (MapView) findViewById(R.id.mView);
}
28
定義 initMapView()方法:設定內建縮放控制器,設定初始縮放等級為 19
(最大為 21),以自己的地理位置為地圖的中心,將自己地理位置的圖層 mlOverlay(一個藍點)疊在 Google Maps 之上。
private void initMapView() {
mView.setBuiltInZoomControls(true);
mControl = mView.getController();
mlOverlay = new MyLocationOverlay(this, mView);
mlOverlay.runOnFirstFix(new Runnable() {
public void run() {
Toast.makeText(SaysApp.this, getString(R.string.howto1), Toast.LENGTH_LONG).show();
Toast.makeText(SaysApp.this, getString(R.string.howto2), Toast.LENGTH_LONG).show();
29
設定發言按鈕:當按鈕被按下,首先檢查名稱輸入框及訊息輸入框,是否 未被輸入或含有換行字元,若無錯誤輸入,則開始執行 sync()方法同步資料,
及 mark()方法標記資訊。
sayButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String name = nameET.getText().toString().trim();
String message = messageET.getText().toString().trim();
if (name.contains("\n") || message.contains("\n")
|| name.equals("") || message.equals("")
|| name.equals("You")
|| message.equals("Say something!")) {
Toast.makeText(SaysApp.this, getString(R.string.suggestion), Toast.LENGTH_LONG).show();
30
定義 sync()方法:開啟伺服器上的POST.PHP 以存取資料庫,先將使用者
的名稱 name、訊息 message、經度longitude、緯度latitude插入 contacts 資料表。
再將網頁回應的字串,即 contacts 資料表的查詢結果,用換行字元做為分割依 據,存入字串陣列stringArray。
private void sync() {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://11.22.33.44/POST.PHP");
try {
List<NameValuePair> nameValuePairs = new
ArrayList<NameValuePair>(4);
nameValuePairs.add(new BasicNameValuePair("name",
nameET.getText().toString().trim()));
nameValuePairs.add(new BasicNameValuePair("message",
messageET.getText().toString().trim()));
nameValuePairs.add(new BasicNameValuePair("longitude", String .valueOf(mlOverlay.getMyLocation().getLongitudeE6())));
nameValuePairs.add(new BasicNameValuePair("latitude", String .valueOf(mlOverlay.getMyLocation().getLatitudeE6())));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse httpresponse = httpclient.execute(httppost);
String httpresponseString = EntityUtils.toString(httpresponse .getEntity());
stringArray = httpresponseString.split("\n");
31
} catch (ClientProtocolException e) { } catch (IOException e) {
} }
定義 mark()方法:使用 Android 作業系統內建的人形圖示來標示資訊,將 標記資訊的圖層 saysoverlay疊在 Google Maps 之上。
private void mark() {
Drawable marker = getResources().getDrawable(
android.R.drawable.ic_menu_myplaces);
saysoverlay = new MarkerOverlay(marker);
mView.getOverlays().add(saysoverlay);
}
宣 告標記 資訊的 圖層類 別: 宣告標記資訊的圖層 saysoverlay 的 類別 MarkerOverlay 繼承 ItemizedOverlay<OverlayItem>類別,使用迴圈將字串陣列
stringArray 內的資訊一一填入標記資訊的對應欄位,最後設定當使用者觸碰資
訊所在的地理位置時,浮現出該資訊內的名稱及訊息。
private class MarkerOverlay extends ItemizedOverlay<OverlayItem> { private List<OverlayItem> olItems = new ArrayList<OverlayItem>();
public MarkerOverlay(Drawable defaultMarker) { super(boundCenterBottom(defaultMarker));
int saysIndex = 0;
32
do {
GeoPoint geopoint = new GeoPoint(
Integer.valueOf(stringArray[saysIndex + 4]), Integer.valueOf(stringArray[saysIndex + 3]));
olItems.add(new OverlayItem(geopoint,
stringArray[saysIndex+ 1], stringArray[saysIndex + 2]));
saysIndex = saysIndex + 5;
} while (saysIndex < stringArray.length);
populate();
}
@Override
protected OverlayItem createItem(int i) { return olItems.get(i);
}
@Override
public int size() {
return olItems.size();
}
@Override
protected boolean onTap(int index) { Toast.makeText(
SaysApp.this,
olItems.get(index).getTitle() + "\nsays\n"
+ olItems.get(index).getSnippet(), Toast.LENGTH_LONG).show();
33
return true;
} }
在 Java 程式碼的最後面,設定 SaysApp 當暫停及回復時,停用及啟用定位 功能。以及設定位移路徑不顯示。
@Override
protected void onResume() { super.onResume();
mlOverlay.enableMyLocation();
}
@Override
protected void onPause() { super.onPause();
mlOverlay.disableMyLocation();
}
@Override
protected boolean isRouteDisplayed() { return false;
}
34
SaysApp 的 Java 程式碼如以上所述。另外,在 AndroidManifest.XML 權限 清單中,要加入以下權限設定,才能使用 GPS 定位、AP 或基地台定位、模擬 器定位、網路連線、Google Maps。
<uses-permission android:name=
"android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name=
"android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name=
"android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name=
"android.permission.INTERNET" />
<uses-library android:name=
"com.google.android.maps" />
35