Android之googleMap(其二)

來源:互聯網
上載者:User

 上文說到擷取手機所在地的經緯度,那麼有幾種方式呢?通過GPS,network.而地位API中提供了LocationManager,以及Location。其中LocationManager用來獲得位置服務,Location用來擷取位置。具體代碼如下:

View Code

 private GeoPoint getGeoPoint(){
LocationManager locationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);
Location location=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
return new GeoPoint((int)location.getLatitude(),(int)location.getLongitude());
}

從這裡我們可以知道一個經緯度對象GeoPoint,它接受2個整形的經緯度值。在這裡我們是使用GPS擷取當前經緯度,如果用network呢?那麼久換LocationManager.NETWORK_PROVIDER

當然,我們可能要考慮到更多的情況,比如說GPS模式是關閉的,那麼如何啟動它?很簡單,我們只要判斷是否啟用了GPS,如果沒有則跳到Settings中進行啟用。代碼如下:

View Code

boolean flag=locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(!flag){
Intent intent=new Intent(Settings.ACTION_SECURITY_SETTINGS);
}

以上是獲得當前手機所在地的經緯度。

 當然當我們行走時候,位置是不斷變化的,我們怎麼才能夠檢測到位置的變化,並顯示出來呢?

我們這裡需要用到位置監聽器LocationListener,當然,我們會查詢出最佳的資料,因此需要設定Criteria

代碼如下:

View Code

//獲得最佳服務
private Criteria getCriteria(){
Criteria criteria=new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);// 高精度
criteria.setAltitudeRequired(false);//海拔
criteria.setBearingRequired(false);//地軸線
criteria.setCostAllowed(false); //付費
criteria.setPowerRequirement(Criteria.POWER_LOW);//電量低
return criteria;
}

 執行個體化LocationListener,在不同的回呼函數中處理,這裡我們只處理位置變化回呼函數onLocationChanged,具體代碼如下:

View Code

//位置監聽器,監聽位置的改變
LocationListener locationListener=new LocationListener(){
//當位置變化時候激發
@Override
public void onLocationChanged(Location location) {
//根據位置擷取經緯度對象
getGeoPoint(location);
}
//GPS,或者network可時候激發
@Override
public void onProviderDisabled(String provider) {


}
//GPS,或者network不可時候激發
@Override
public void onProviderEnabled(String provider) {


}
//GPS,或者network狀態改變時候激發
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
switch(status){
case LocationProvider.OUT_OF_SERVICE:
//不在服務
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
//暫不可用
break;
case LocationProvider.AVAILABLE :
//可用
break;

}

}
};

既然定義好了監聽處理類後,我們就可以在LocationManager中註冊這個監聽:

View Code

private void registeListener(){
LocationManager locationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);
if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
//如果GPS不可用,則跳轉到Settings中進行設定
Intent intent=new Intent(Settings.ACTION_SECURITY_SETTINGS);
startActivity(intent);
}
//查詢最設和的服務資訊
String provider=locationManager.getBestProvider(getCriteria(), true);
//設定位置監聽器,間隔5秒改變一次
locationManager.requestLocationUpdates(provider, 5000, 0, locationListener);
}

這裡locationManager.requestLocationUpdates(provider, 5000, 0, locationListener); 第一個參數是位置提供器,第2個是多少毫米請求一次,第3個是移動最小距離(米),第4個就是監聽類了。

當然,我們可以取消位置監聽:locationManager.removeUpdates(locationListener);

既然可以動態擷取手機經緯度,那麼怎麼把經緯度解析成我們實際地址呢?
我們可以採用Geocoder類的getFromLocation方法解析位置資訊,然後返回一系列地址資訊List<Address>,再根據最符合的Address擷取國家、州縣、街道等等地址資訊,代碼如下:

View Code

//根據經緯度獲得地址(國家,州縣,街道等等)
private void showAddressFromGeoPoint(GeoPoint gPoint) throws IOException{
StringBuilder sb=new StringBuilder();
Geocoder geoCode=new Geocoder(this,Locale.getDefault());
List<Address> addresses=geoCode.getFromLocation(gPoint.getLatitudeE6()/1E6, gPoint.getLongitudeE6()/1E6, 1);
if(addresses.size()>0){
Address address=addresses.get(0);
for(int i=0;i<address.getMaxAddressLineIndex();i++){
sb.append(address.getAddressLine(i)+"\n");
}
sb.append(address.getLocality()+"\n");
sb.append(address.getPostalCode()+"\n");
sb.append(address.getCountryName()+"\n");

Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
}
}

以上是把經緯度、位置等資訊解析成地址,那麼反過來,我們是不是可以根據位址名稱獲得經緯度位置,然後在地圖上標識起來呢?當然可以,現在就來根據實際地址擷取經緯度吧:

跟上述方式一樣,調用Geocoder的getFromLocationName方法,獲得地址清單,然後取出最佳的地址,再擷取經緯度,代碼如下:

View Code

 //根據地址擷取經緯度資訊GeoPoint
private GeoPoint getGeoPointFromAddressName(String locationName) throws IOException{
Geocoder geoCode=new Geocoder(this,Locale.getDefault());
List<Address> addresses=geoCode.getFromLocationName(locationName, 1);
if(addresses!=null){
double lati=addresses.get(0).getLatitude();
double longi=addresses.get(0).getLongitude();
return new GeoPoint((int)(lati*1E6),(int)(longi*1E6));
}
return null;
}

如果,我想知道,我是否逼近了某個地區範圍,然後手機就發出通知,這個怎麼辦?

逼近某個範圍,就是有一個經緯度對象GeoPoint 固定,另外一個GeoPoint 不斷靠近變化,要測量這2個點的距離,可以使用Location的distanceBetween方法。具體代碼如下:

View Code

 //計算2點距離,經緯度
private float getDistance(GeoPoint startPoint,GeoPoint endPoint){
float []results=new float[3];
Location.distanceBetween(startPoint.getLatitudeE6()/1E6, startPoint.getLongitudeE6()/1E6,
endPoint.getLatitudeE6()/1E6, endPoint.getLongitudeE6()/1E6,
results);
return results[0];
}

上述代碼就實現了2個點距離檢測,然後我們可以根據判斷2點距離是否在某一距離範圍內,代碼如下:

View Code

//判斷是否在多少米範圍內
private boolean isNearAround(GeoPoint startPoint,GeoPoint endPoint,float meter){
float distance=getDistance(startPoint,endPoint);
return (meter-distance>0)?true:false;
}

以上就是逼近某地範圍的方法,但是你可能會想,我們的位置如果是變化的呢?所以你就必須在位置變化時候更新GeoPoint ,位置變化監聽器LocationListener有個onLocationChanged方法回調每次變化的位置,當然你看了以上說明後自然知道怎麼調用了。

再來幾個開發中常會遇到問題吧。

我們怎麼擷取手機螢幕上一點對應的經緯度?(手機螢幕點轉化為經緯度)或者某一經緯度怎麼對應手機螢幕上一點的位置?

我們可以使用Projection類的fromPixels,以及toPixels方法分別轉化為螢幕一點,以及螢幕一點的經緯度,當然擷取 Projection是需要我們地圖對象的getProjection方法,具體代碼如下:

View Code

//螢幕上一點獲得經緯度
private GeoPoint FormScreenPoint(Point screen){
Projection projection=mapView.getProjection();
GeoPoint gpoint=projection.fromPixels(screen.x, screen.y);
return gpoint;
}

//根據經緯度定位到手機螢幕上一點
private Point FromGeoPoint(GeoPoint gPoint){
Point out =new Point();
Projection projection=mapView.getProjection();
projection.toPixels(gPoint, out);
return out;
}

有了前面幾項基礎知識後,我們可以更深入發展了,就想之前提及的,在手機螢幕上繪製一個圖層,標記一張圖片或者一些資訊,然後我們點擊這個標記,他會提示一些資訊。
這裡主要就是如何解決標記到地圖的問題了
這裡使用到一個類Overlay,這個可作為地圖上的標記,因此我們首先基礎這個標記,然後繪製自己的圖釘(圖片),再重寫它的onTouchEvent方法,以便點擊這個圖層時候提示資訊,當然我們可以傳遞經緯度對象GeoPoint進去,以便在地圖中顯示:

View Code

//自訂圖層標記
private class MyOverLay extends Overlay{
GeoPoint in=null;
public MyOverLay(GeoPoint in){
this.in=in;
}
//在自訂繪製圖層的方法中添加圖釘(一張圖片)
@Override
public boolean draw(Canvas canvas,MapView mapView,
boolean shadow,long when){
//經緯度轉化螢幕一點
Point out=new Point();
Projection proj=mapView.getProjection();
proj.toPixels(in, out);

//獲得圖片並調用canvas繪製圖片,其中第3個參數為Y軸座標具體看圖
Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, out.x, out.y-50, null);
return true;
}

@Override
public boolean onTouchEvent(MotionEvent e,MapView mapView){
if(e.getAction()==MotionEvent.ACTION_UP){
//根據螢幕一點擷取經緯度
GeoPoint gpoint=mapView.getProjection().fromPixels((int)e.getX(), (int)e.getY());
//然後顯示經緯度
String msg="您點擊的地方經度為:"+gpoint.getLatitudeE6()/1E6+",緯度為:"+gpoint.getLongitudeE6()/1E6;
Toast.makeText(getApplication(), msg, Toast.LENGTH_LONG).show();

//當然,您可以使用傳遞過來的對象,比如GeoPoint擷取一些其他自訂對象資訊,比如說什麼地方,什麼公司以及風景區等

}
return true;
}
}

我們可以看到我們繪製了一個圖形,以及重寫了觸摸的方法,在觸摸時候提示資訊,接下來,我們必須把它“釘”在地圖上進行顯示,當然了,預設MapView都自動載入了圖層,我們只需調用
List<Overlay> overlays=mapView.getOverlays(); 方法獲得圖層列表,然後把我們自訂的圖層添加進去即可,代碼如下:

View Code

 //在螢幕上打上標記(圖釘)
private void putOverLay(GeoPoint in){
// /定義標記
MyOverLay myOverLay=new MyOverLay(in);
List<Overlay> overlays=mapView.getOverlays();
overlays.clear();
overlays.add(myOverLay);
mapView.invalidate();
}

 這裡解析一個問題,我們說是canvas.drawBitmap(bitmap, out.x, out.y-50, null);中第3個參數是要減去50呢?你看看這幅圖就明白了,需要減去高才可以使圖釘的指標正好對應螢幕的某點。

完成。假如你完全理解上面一系列東西,那麼LBS已經有了基礎。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.