Android Google Map/谷歌地图 接入不完全指南 (一)已良好运行起官方demo和说明注意事项。
一、GoogleMap
谷歌地图使用起来大概分两种方式
1、以fragment的方式使用
2、以控件的方式,也就是原生的GoogleMap
发现,现在google家的地图现在已经有比较全的官方中文文档啦,官方文档是个好东西,我这里小文,只是根据其衍生的出来的东西,毕竟“曾见郭象注庄子,却是庄子注郭象”嘛。
原著就是叼。
一.1 以fragment的方式使用googleMap
image.png.
示例代码
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);
// 移动地图到指定经度的位置
googleMap.moveCamera(CameraUpdateFactory.newLatLng(appointLoc));
//添加标记到指定经纬度
googleMap.addMarker(new MarkerOptions().position(new LatLng(lat, lng)).title("Marker")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.chat_loc_point)));
/*// 点击标记点,默认点击弹出跳转google地图或导航选择,返回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) {
}
});
// 不允许手势缩放
googleMap.getUiSettings().setZoomGesturesEnabled(false);
//googleMap.getUiSettings().setMapToolbarEnabled(false); 禁用精简模式下右下角的工具栏
// 不允许拖动地图
googleMap.getUiSettings().setScrollGesturesEnabled(false);
// 设置缩放级别
CameraUpdate zoom = CameraUpdateFactory.zoomTo(13);
googleMap.animateCamera(zoom);*/
}
}
.
.
对应布局
<?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对象,调用getMapAsync异步读取地图 -
第三步,在getMapAsync的OnMapReadyCallback接口中的onMapReady方法中指定经纬度和marker。
.
默认效果
默认效果
1、可双指缩放
2、可单指移动
3、带有指南针的,
4、maker点是点击的,点击后弹出toolbar(此toolbar是地图的toobar,即跳转googlemap app或者导航)
5、双击放大
我们可以获取UiSettings或者利用googleMap对象直接设置。
代码的备注里面我也简单列举了一些,可以参见官网文档进行调整。
如果不需要这些东西,就要特别简单的地图,那么我们可以使用精简模式。
精简模式
如果我们不想要默认的效果,那么我们完全可以使用精简模式。
- 使用方式
image.png1、fragment布局代码中 map:liteMode="true"
2、java代码里面配置GoogleMapOptions options = new GoogleMapOptions().liteMode(true);
- 精简模式与默认的地图toolbar
我们使用精简模式之后,右下角的地图的Toolbar自己就跑出来了,我们可以通过UiSettings().setMapToolbarEnabled(false);
把Toolbar禁掉,就不会出现了。
如果你说为什么使用精简模式之后地图不是居中了,那时因为缩放关系导致的,你只要把缩放级别调整一下就好
// 设置缩放级别
CameraUpdate zoom = CameraUpdateFactory.zoomTo(13);
googleMap.animateCamera(zoom);
zoomTo(float),因为默认的太小,看到是世界地图,只要放大到可以铺满屏幕,大概3-5之间吧,就不会出现上下空白仅有中间的情况。
嗯,fragment大概到这里。
一.2 MapView
亦可参见源例
.
.
MapView
MapView 是 Android View 类的一个子类, 用于在 Android View 中放置地图。 View 表示屏幕的某个矩形区域, 是 Android 应用和小工具的基本构建基块。 MapView 与 MapFragment 很相似,它也充当地图容器,通过 GoogleMap 对象公开核心地图功能。
在完全交互模式下使用该 API 时,MapView 类的用户必须将下列 Activity 生命周期方法转发给 MapView 类中的相应方法:onCreate()、onStart()、onResume()、onPause()、onStop()、onDestroy()、onSaveInstanceState() 和 onLowMemory()。
例子
image.png.
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的大概就到这里,声明周期对于MapView很重要。
二、自动获取经纬度和逆地理编码
定位,一种是官方的My Location,主要使用方式是 mMap.setMyLocationEnabled(true);
My Location官方文档 位置数据
My Location demo
但是在这种方式只是地图层面地获取“我的位置”,My Location 层不会返回任何数据,这往往不是我们要的,所以这里略过,想了解可以看上面的两个链接。
FusedLocationProviderApi
编码获取位置现在比较好的方式是使用 [FusedLocationProviderApi ],因为它提供了比旧式的LocationManager API更加方便更加省电的方式。另外,如果你已经在谷歌地图上使用谷歌Play服务,就没有理由不使用它了。
使用FusedLocationProviderApi,就需要在gradle引入play-services,比如
compile 'com.google.android.gms:play-services:10.2.6'
而引入play-services,可能报multiDex
那么我们需要配置一下主mudule的gradle
// 添加之
multiDexEnabled true
// 添加之
dexOptions {
incremental true
javaMaxHeapSize "4g"
}
一般即可解决。
接下来我们来写一个demo,功能是
进入页面自动获取当前经纬度,拿到经纬度之后进行逆地理编码,得到地址
获取当前位置经纬度
我们要利用FusedLocationApi获取当前位置,其实核心就是调用下面这几行代码,
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
addConnectionCallbacks
而这个build的过程最主要的就是addConnectionCallbacks
方法,传入的GoogleApiClient.ConnectionCallbacks接口要求我们实现如下两个方法
- 1、
onConnected
异步进行连接,获取位置 (关键方法) - 2、onConnectionSuspended 当客户端断开
.
.
addOnConnectionFailedListener
其他的,addOnConnectionFailedListener传入的GoogleApiClient.OnConnectionFailedListener实现的onConnectionFailed方法当然是连接失败时调用,这点没其他特别的。
gif
myloc.gifpublic 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("位置", "得到位置当前" + address + "'\n"
+ "经度:" + String.valueOf(address.get(0).getLongitude()) + "\n"
+ "纬度:" + String.valueOf(address.get(0).getLatitude()) + "\n"
+ "纬度:" + "国家:" + 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>
最后把流程画一下
GoogleMap地理编码与逆地理编码.png核心代码在此,根据上面的代码,即可实现自动定位,获取经纬度并且得到地址位置信息。
当前地点为东南亚,经测试,安卓5.0,6.0和7.1均可良好运行,其他国家地区应该也可以。大天朝除外。
二、小细节
1、在google控制台创建项目默认是不开启包括地图在内的任何api的,请开启对应功能,不然无法显示地图,开启方法请看Android Google Map/谷歌地图 接入不完全指南 (一)。
2、android API23 以上请做好权限申请工作,避免因为权限问题导致的闪退。
.
本篇大概多少到这里,下一遍是关于列表的
Android GoogleMap不完全指南 (三)
本文完。
网友评论