Android Google Map/谷歌地圖 接入不完全指南 (一)已良好運(yùn)行起官方demo和說明注意事項(xiàng)。
一列赎、GoogleMap
谷歌地圖使用起來大概分兩種方式
1忽冻、以fragment的方式使用
2唬血、以控件的方式,也就是原生的GoogleMap
發(fā)現(xiàn)棍厂,現(xiàn)在google家的地圖現(xiàn)在已經(jīng)有比較全的官方中文文檔啦,官方文檔是個(gè)好東西超陆,我這里小文牺弹,只是根據(jù)其衍生的出來的東西,畢竟“曾見郭象注莊子时呀,卻是莊子注郭象”嘛张漂。
原著就是叼。
一.1 以fragment的方式使用googleMap
.
示例代碼
SimpleFragmentModeActivity
public class SimpleFragmentModeActivity extends AppCompatActivity implements OnMapReadyCallback {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_mode);
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
double lat = 0.0;
double lng = 0.0;
LatLng appointLoc = new LatLng(lat, lng);
// 移動(dòng)地圖到指定經(jīng)度的位置
googleMap.moveCamera(CameraUpdateFactory.newLatLng(appointLoc));
//添加標(biāo)記到指定經(jīng)緯度
googleMap.addMarker(new MarkerOptions().position(new LatLng(lat, lng)).title("Marker")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.chat_loc_point)));
/*// 點(diǎn)擊標(biāo)記點(diǎn)退唠,默認(rèn)點(diǎn)擊彈出跳轉(zhuǎn)google地圖或?qū)Ш竭x擇鹃锈,返回true則不彈出
googleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
return true;
}
});
// 單擊
googleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
}
});
// 不允許手勢(shì)縮放
googleMap.getUiSettings().setZoomGesturesEnabled(false);
//googleMap.getUiSettings().setMapToolbarEnabled(false); 禁用精簡(jiǎn)模式下右下角的工具欄
// 不允許拖動(dòng)地圖
googleMap.getUiSettings().setScrollGesturesEnabled(false);
// 設(shè)置縮放級(jí)別
CameraUpdate zoom = CameraUpdateFactory.zoomTo(13);
googleMap.animateCamera(zoom);*/
}
}
.
.
對(duì)應(yīng)布局
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
.
.
使用步驟
第一步
布局為文件放上fragment,注意class="com.google.android.gms.maps.SupportMapFragment"
不可或缺第二步
得到SupportMapFragment對(duì)象瞧预,調(diào)用getMapAsync異步讀取地圖第三步屎债,在getMapAsync的OnMapReadyCallback接口中的onMapReady方法中指定經(jīng)緯度和marker。
.
默認(rèn)效果
默認(rèn)效果
1垢油、可雙指縮放
2盆驹、可單指移動(dòng)
3、帶有指南針的滩愁,
4躯喇、maker點(diǎn)是點(diǎn)擊的,點(diǎn)擊后彈出toolbar(此toolbar是地圖的toobar硝枉,即跳轉(zhuǎn)googlemap app或者導(dǎo)航)
5廉丽、雙擊放大
我們可以獲取UiSettings或者利用googleMap對(duì)象直接設(shè)置。
代碼的備注里面我也簡(jiǎn)單列舉了一些妻味,可以參見官網(wǎng)文檔進(jìn)行調(diào)整正压。
如果不需要這些東西,就要特別簡(jiǎn)單的地圖责球,那么我們可以使用精簡(jiǎn)模式焦履。
精簡(jiǎn)模式
如果我們不想要默認(rèn)的效果拓劝,那么我們完全可以使用精簡(jiǎn)模式僻焚。
- 使用方式
1月趟、fragment布局代碼中 map:liteMode="true"
2、java代碼里面配置GoogleMapOptions options = new GoogleMapOptions().liteMode(true);
- 精簡(jiǎn)模式與默認(rèn)的地圖toolbar
我們使用精簡(jiǎn)模式之后惋砂,右下角的地圖的Toolbar自己就跑出來了屑宠,我們可以通過UiSettings().setMapToolbarEnabled(false);
把Toolbar禁掉厢洞,就不會(huì)出現(xiàn)了。
如果你說為什么使用精簡(jiǎn)模式之后地圖不是居中了侨把,那時(shí)因?yàn)榭s放關(guān)系導(dǎo)致的犀变,你只要把縮放級(jí)別調(diào)整一下就好
// 設(shè)置縮放級(jí)別
CameraUpdate zoom = CameraUpdateFactory.zoomTo(13);
googleMap.animateCamera(zoom);
zoomTo(float),因?yàn)槟J(rèn)的太小秋柄,看到是世界地圖获枝,只要放大到可以鋪滿屏幕,大概3-5之間吧骇笔,就不會(huì)出現(xiàn)上下空白僅有中間的情況省店。
嗯,fragment大概到這里笨触。
一.2 MapView
亦可參見源例
.
.
MapView
MapView 是 Android View 類的一個(gè)子類懦傍, 用于在 Android View 中放置地圖。 View 表示屏幕的某個(gè)矩形區(qū)域芦劣, 是 Android 應(yīng)用和小工具的基本構(gòu)建基塊粗俱。 MapView 與 MapFragment 很相似,它也充當(dāng)?shù)貓D容器虚吟,通過 GoogleMap 對(duì)象公開核心地圖功能寸认。
在完全交互模式下使用該 API 時(shí),MapView 類的用戶必須將下列 Activity 生命周期方法轉(zhuǎn)發(fā)給 MapView 類中的相應(yīng)方法:onCreate()串慰、onStart()偏塞、onResume()、onPause()邦鲫、onStop()灸叼、onDestroy()、onSaveInstanceState() 和 onLowMemory()庆捺。
例子
.
SimpleMapActivity
public class SimpleMapActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mMapView;
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_raw_map);
// *** IMPORTANT ***
// MapView requires that the Bundle you pass contain _ONLY_ MapView SDK
// objects or sub-Bundles.
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
mMapView = (MapView) findViewById(R.id.mMapView);
mMapView.onCreate(mapViewBundle);
mMapView.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap map) {
double lat = 39.937795;
double lng = 116.387224;
LatLng appointLoc = new LatLng(lat, lng);
map.addMarker(new MarkerOptions().position(appointLoc).title("Marker"));
map.moveCamera(CameraUpdateFactory.newLatLng(appointLoc));
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle mapViewBundle = outState.getBundle(MAPVIEW_BUNDLE_KEY);
if (mapViewBundle == null) {
mapViewBundle = new Bundle();
outState.putBundle(MAPVIEW_BUNDLE_KEY, mapViewBundle);
}
mMapView.onSaveInstanceState(mapViewBundle);
}
@Override
protected void onResume() {
super.onResume();
mMapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mMapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mMapView.onStop();
}
@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}
@Override
protected void onDestroy() {
mMapView.onDestroy();
super.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
}
.
.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Raw Map"
android:textSize="30sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
/>
<com.google.android.gms.maps.MapView
android:id="@+id/mMapView"
android:layout_width="200dp"
android:layout_height="150dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:background="#66ff0000"
>
</com.google.android.gms.maps.MapView>
</LinearLayout>
.
.
MapView的大概就到這里古今,聲明周期對(duì)于MapView很重要。
二滔以、自動(dòng)獲取經(jīng)緯度和逆地理編碼
定位沧卢,一種是官方的My Location,主要使用方式是 mMap.setMyLocationEnabled(true);
My Location官方文檔 位置數(shù)據(jù)
My Location demo
但是在這種方式只是地圖層面地獲取“我的位置”醉者,My Location 層不會(huì)返回任何數(shù)據(jù)但狭,這往往不是我們要的,所以這里略過撬即,想了解可以看上面的兩個(gè)鏈接立磁。
FusedLocationProviderApi
編碼獲取位置現(xiàn)在比較好的方式是使用 [FusedLocationProviderApi ],因?yàn)樗峁┝吮扰f式的LocationManager API更加方便更加省電的方式剥槐。另外唱歧,如果你已經(jīng)在谷歌地圖上使用谷歌Play服務(wù),就沒有理由不使用它了粒竖。
使用FusedLocationProviderApi颅崩,就需要在gradle引入play-services,比如
compile 'com.google.android.gms:play-services:10.2.6'
而引入play-services蕊苗,可能報(bào)multiDex
那么我們需要配置一下主mudule的gradle
// 添加之
multiDexEnabled true
// 添加之
dexOptions {
incremental true
javaMaxHeapSize "4g"
}
一般即可解決沿后。
接下來我們來寫一個(gè)demo,功能是
進(jìn)入頁(yè)面自動(dòng)獲取當(dāng)前經(jīng)緯度朽砰,拿到經(jīng)緯度之后進(jìn)行逆地理編碼尖滚,得到地址
獲取當(dāng)前位置經(jīng)緯度
我們要利用FusedLocationApi獲取當(dāng)前位置,其實(shí)核心就是調(diào)用下面這幾行代碼瞧柔,
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
addConnectionCallbacks
而這個(gè)build的過程最主要的就是addConnectionCallbacks
方法漆弄,傳入的GoogleApiClient.ConnectionCallbacks接口要求我們實(shí)現(xiàn)如下兩個(gè)方法
- 1、
onConnected
異步進(jìn)行連接造锅,獲取位置 (關(guān)鍵方法) - 2撼唾、onConnectionSuspended 當(dāng)客戶端斷開
.
.
addOnConnectionFailedListener
其他的,addOnConnectionFailedListener傳入的GoogleApiClient.OnConnectionFailedListener實(shí)現(xiàn)的onConnectionFailed方法當(dāng)然是連接失敗時(shí)調(diào)用哥蔚,這點(diǎn)沒其他特別的倒谷。
gif
public class SimpleMyLocActivity extends AppCompatActivity implements
OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
LatLng latLng;
GoogleMap mGoogleMap;
SupportMapFragment mMapFragment;
Marker mCurrLocation;
private static final int REQUESTCODE = 6001;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_loc);
mMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mMapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
// 允許獲取我的位置
try {
mGoogleMap.setMyLocationEnabled(true);
} catch (SecurityException e) {
e.printStackTrace();
}
buildGoogleApiClient();
mGoogleApiClient.connect();
}
@Override
public void onPause() {
super.onPause();
//Unregister for location callbacks:
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
}
});
}
}
protected synchronized void buildGoogleApiClient() {
Toast.makeText(this, "buildGoogleApiClient", Toast.LENGTH_SHORT).show();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
@Override
public void onConnected(Bundle bundle) {
Toast.makeText(this, "onConnected", Toast.LENGTH_SHORT).show();
Location mLastLocation = null;
try {
Log.i("位置", LocationServices.FusedLocationApi.getLocationAvailability(mGoogleApiClient) + "");
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
} catch (SecurityException e) {
e.printStackTrace();
}
if (mLastLocation != null) {
//place marker at current position
mGoogleMap.clear();
latLng = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()), 15));
// 添加marker,但是這里我們特意把marker弄成透明的
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.chat_loc_point));
mCurrLocation = mGoogleMap.addMarker(markerOptions);
Log.i("位置", mLastLocation + "1111111");
Log.i("位置", "最新的位置 getProvider " + mLastLocation.getProvider());
Log.i("位置", "最新的位置 getAccuracy " + mLastLocation.getAccuracy());
Log.i("位置", "最新的位置 getAltitude " + mLastLocation.getAltitude());
Log.i("位置", "最新的位置 Bearing() " + mLastLocation.getBearing());
Log.i("位置", "最新的位置 Extras() " + mLastLocation.getExtras());
Log.i("位置", "最新的位置 Latitude() " + mLastLocation.getLatitude());
Log.i("位置", "最新的位置 Longitude()() " + mLastLocation.getLongitude());
Log.i("位置", " ============= ");
TextView mTvAddress = (TextView) findViewById(R.id.mTvAddress);
String address = getAddress(SimpleMyLocActivity.this, mLastLocation.getLatitude(), mLastLocation.getLongitude());
mTvAddress.setText(address);
}
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(5000); //5 seconds
mLocationRequest.setFastestInterval(3000); //3 seconds
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
//mLocationRequest.setSmallestDisplacement(0.1F); //1/10 meter
//LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
}
});
}
@Override
public void onConnectionSuspended(int i) {
Toast.makeText(this, "onConnectionSuspended", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(this, "onConnectionFailed", Toast.LENGTH_SHORT).show();
}
/**
* 逆地理編碼 得到地址
* @param context
* @param latitude
* @param longitude
* @return
*/
public static String getAddress(Context context, double latitude, double longitude) {
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
try {
List<android.location.Address> address = geocoder.getFromLocation(latitude, longitude, 1);
Log.i("位置", "得到位置當(dāng)前" + address + "'\n"
+ "經(jīng)度:" + String.valueOf(address.get(0).getLongitude()) + "\n"
+ "緯度:" + String.valueOf(address.get(0).getLatitude()) + "\n"
+ "緯度:" + "國(guó)家:" + address.get(0).getCountryName() + "\n"
+ "城市:" + address.get(0).getLocality() + "\n"
+ "名稱:" + address.get(0).getAddressLine(1) + "\n"
+ "街道:" + address.get(0).getAddressLine(0)
);
return address.get(0).getAddressLine(0) + " " + address.get(0).getLocality() + " " + address.get(0).getCountryName();
} catch (Exception e) {
e.printStackTrace();
return "未知";
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUESTCODE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mGoogleApiClient.connect();
} else {
}
return;
}
}
}
}
.
.
.
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_weight="1">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.gmapdemo2.googlemapdemosimple.MapsActivity"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" >
</fragment>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:layout_centerVertical="true"
android:src="@drawable/poi_marker_pressed"/>
</RelativeLayout>
<TextView
android:id="@+id/mTvAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
tools:text="123123"
android:background="#ffffff"
android:gravity="center"
android:textColor="#0000ff"
android:paddingTop="20dp"
/>
</LinearLayout>
最后把流程畫一下
核心代碼在此肺素,根據(jù)上面的代碼恨锚,即可實(shí)現(xiàn)自動(dòng)定位,獲取經(jīng)緯度并且得到地址位置信息倍靡。
當(dāng)前地點(diǎn)為東南亞猴伶,經(jīng)測(cè)試,安卓5.0塌西,6.0和7.1均可良好運(yùn)行他挎,其他國(guó)家地區(qū)應(yīng)該也可以。大天朝除外捡需。
二办桨、小細(xì)節(jié)
1、在google控制臺(tái)創(chuàng)建項(xiàng)目默認(rèn)是不開啟包括地圖在內(nèi)的任何api的站辉,請(qǐng)開啟對(duì)應(yīng)功能呢撞,不然無法顯示地圖损姜,開啟方法請(qǐng)看Android Google Map/谷歌地圖 接入不完全指南 (一)。
2殊霞、android API23 以上請(qǐng)做好權(quán)限申請(qǐng)工作摧阅,避免因?yàn)闄?quán)限問題導(dǎo)致的閃退。
.
本篇大概多少到這里绷蹲,下一遍是關(guān)于列表的
Android GoogleMap不完全指南 (三)
本文完棒卷。