专栏目录
- 第一节 自定义轮播图的制作
- 第二节 底部导航栏菜单,炫酷菜单动画,背景变暗、按钮焦点获取
- 第三节 适配Android10的拍照、从相册获取代码,包括完整的权限申请和图片地址获取
- 第四节 百度定位、地图SDK,和风天气获取教程
- 第五节 微信朋友圈式九宫格添加图片展示(待更新)
- 第六节 第三方api获取淘宝数据,用RecyclerView进行商品展示、刷新和搜索(待更新)
引言
在安卓开发中,我们经常会用到调用地图、定位的API,并且还可能会通过定位来获取当前位置的地址。下面我将带领大家一步步对这些常见的API的调用做一个总结。
效果图
利用百度地图SDK获取经纬度
定位SDK的核心能力就是帮助开发者快速、精准的获取用户定位信息。开发者只需按照如下流程操作,即可获取用户当前经纬度。
一、准备工作
在使用定位SDK进行具体开发工作之前,需获取密钥(AK),并对开发工程进行环境配置工作。 此外,Google在Android 6.0中引入了动态权限获取机制,开发者在使用定位SDK之前,请详细了解关于Android 6.0系统开发须知。
1.注册和获取密钥
只要注册一个普通的百度账号即可,注册完登录网址
获取AK的流程大致可分为如下四个步骤:
(1)登录API控制台;
(2)创建应用;
(3)配置SHA1和包名;
(4)提交生成AK。
详细内容请参考百度开发文档
2.添加SDK(jar + so)
下载Android定位SDK并解压,将libs中的jar和so放置到工程中相应的位置。
注意,Android定位SDK提供了多种CPU架构的so文件(jar通用,只有一个),开发者可根据实际使用需求,放置所需so到对应的工程文件夹内。
注:jar文件是你在activity中调用的各种定位方法,.so文件是用来适配cpu架构的,需要根据你的需求选用合适so文件,不确定的话就把所有的类型都加上。
下图是so文件存放的位置,你需要在app下创建一个jniLibs文件家(名字必须是这个),文件夹下的目录就是五种cpu架构,我们需要将对应架构的.so文件放在对应文件夹下。
jar文件放在libs文件夹下。
.so文件和jar文件下载
链接:https://pan.baidu.com/s/1zyWNe4k6sXTd53nzR0yL3g
提取码:gzay
复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V4的分享
3.配置build.gradle文件
放在下面的文件夹的android{}里面
sourceSets{
main{
jniLibs.srcDir 'libs'
jni.srcDirs = [] //disable automatic ndk-build
}
}
4.添加AK
Android定位SDK自v4.0版本起,需要进行AK鉴权。开发者在使用SDK前,需完成AK申请,并在AndroidManifest.xml文件中,正确填写AK。
在Application标签中增加如下代码:
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="YourAK" >
</meta-data>
5.添加定位权限
使用定位SDK,需在AndroidManifest.xml文件中Application标签中声明service组件,每个App拥有自己单独的定位service,代码如下:
<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote"> </service>
除添加service组件外,使用定位SDK还需添加如下权限:
<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
二、开始实现定位功能
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TextView textView2;
private TextView textView3;
private Button button;
private String address;
double latitude;
double longitude;
public LocationClient mLocationClient = null;
private MyLocationListener myListener = new MyLocationListener();
//BDAbstractLocationListener为7.2版本新增的Abstract类型的监听接口
//原有BDLocationListener接口暂时同步保留。具体介绍请参考后文第四步的说明
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//权限检测和申请工具类
PermissionUtil.getInstance().onCallback(new PermissionUtil.PermissionCallback() {
@Override
public void onGranted(List<String> actions) {
for (String action : actions) {
Log.e("TAG", String.format("onGranted: %s", action));
}
}
@Override
public void onDenied(List<String> actions) {
for (String action : actions) {
Log.e("TAG", String.format("onGranted: %s", action));
}
}
}).requestPermissions(this, new String[]{
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.ACCESS_WIFI_STATE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.INTERNET
});
init();
initLocationClient();
setLocationClientOption();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLocationClient.start(); //开始定位
//mLocationClient为第二步初始化过的LocationClient对象
//调用LocationClient的start()方法,便可发起定位请求
}
});
}
//绑定组件
private void init(){
textView2 = findViewById(R.id.textView2);
textView3 = findViewById(R.id.textView3);
button = findViewById(R.id.button);
}
/**
* 初始化LocationClient类
* 请在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。
* 推荐使用getApplicationConext()方法获取全进程有效的Context。
*/
private void initLocationClient(){
//定位监听器,一旦调用requestLocation()函数,就会触发MyLocationListener()
mLocationClient = new LocationClient(getApplicationContext());
//声明LocationClient类
mLocationClient.registerLocationListener(myListener);
}
/**
* 配置定位SDK参数
* 通过参数配置,可选择定位模式、可设定返回经纬度坐标类型、可设定是单次定位还是连续定位。
* 定位SDK所提供的定位模式包括三种:高精度、低功耗和仅用设备定位。开发者请根据自己的实际使用需求进行选择。
*
* 定位SDK能够返回三种坐标类型的经纬度(国内),分别是GCJ02(国测局坐标)、BD09(百度墨卡托坐标)和BD09ll(百度经纬度坐标)。
* 如果开发者想利用定位SDK获得的经纬度直接在百度地图上标注,请选择坐标类型BD09ll。
*/
private void setLocationClientOption(){
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//可选,设置定位模式,默认高精度
//LocationMode.Hight_Accuracy:高精度;
//LocationMode. Battery_Saving:低功耗;
//LocationMode. Device_Sensors:仅使用设备;
option.setCoorType("bd09ll");
//可选,设置返回经纬度坐标类型,默认GCJ02
//GCJ02:国测局坐标;
//BD09ll:百度经纬度坐标;
//BD09:百度墨卡托坐标;
//海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标
option.setScanSpan(1000);
//可选,设置发起定位请求的间隔,int类型,单位ms
//如果设置为0,则代表单次定位,即仅定位一次,默认为0
//如果设置非0,需设置1000ms以上才有效
option.setOpenGps(true);
//可选,设置是否使用gps,默认false
//使用高精度和仅用设备两种定位模式的,参数必须设置为true
option.setLocationNotify(true);
//可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false
option.setIgnoreKillProcess(false);
//可选,定位SDK内部是一个service,并放到了独立进程。
//设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)
option.SetIgnoreCacheException(false);
//可选,设置是否收集Crash信息,默认收集,即参数为false
option.setWifiCacheTimeOut(5*60*1000);
//可选,V7.2版本新增能力
//如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位
option.setEnableSimulateGps(false);
//可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false
option.setNeedNewVersionRgc(true);
//可选,设置是否需要最新版本的地址信息。默认需要,即参数为true
option.setIsNeedAddress(true);
//可选,是否需要地址信息,默认为不需要,即参数为false
//如果开发者需要获得当前点的地址信息,此处必须为true
option.setNeedNewVersionRgc(true);
//可选,设置是否需要最新版本的地址信息。默认需要,即参数为true
mLocationClient.setLocOption(option);
//mLocationClient为第二步初始化过的LocationClient对象
//需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
//更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明
}
/**
* 实现BDAbstractLocationListener接口
* Android定位SDK自V7.2版本起,对外提供了Abstract类型的监听接口BDAbstractLocationListener,用于实现定位监听。
*/
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location){
//此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
//以下只列举部分获取经纬度相关(常用)的结果信息
//更多结果信息获取说明,请参照类参考中BDLocation类中的说明
latitude = location.getLatitude(); //获取纬度信息
longitude = location.getLongitude(); //获取经度信息
float radius = location.getRadius(); //获取定位精度,默认值为0.0f
String coorType = location.getCoorType();
//获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
int errorCode = location.getLocType();
//获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
address = location.getAddrStr();
textView2.setText(longitude + ", " + latitude);
textView3.setText(address);
mLocationClient.stop();
}
}
}
PermissionUtil工具类
package com.example.mycourse4;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.PermissionChecker;
import java.util.ArrayList;
import java.util.List;
public class PermissionUtil {
private static final String TAG = "PermissionUts";
private final static int request_permission_code = 0x99;
private PermissionCallback permissionCallback;
private Handler mHandler = null;
private static class SingleUts {
private static PermissionUtil uts = new PermissionUtil();
}
private PermissionUtil() {
final HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
}
public static PermissionUtil getInstance() {
return SingleUts.uts;
}
/**
* 请求权限
*
* @param activity
* @param permission
*/
public void requestPermission(Activity activity, String permission) {
if (null == activity || TextUtils.isEmpty(permission)) {
return;
}
if (!verifyPermission(activity, permission)) {
ActivityCompat.requestPermissions(activity, new String[]{permission}, request_permission_code);
}
}
/**
* 请求权限
*
* @param activity
* @param permissions
*/
public void requestPermissions(final Activity activity, final String[] permissions) {
if (null == activity || null == permissions || permissions.length == 0) {
return;
}
ActivityCompat.requestPermissions(activity, permissions, request_permission_code);
}
/**
* 校验权限
*
* @param activity
* @param permission
* @return
*/
public boolean verifyPermission(Activity activity, String permission) {
if (null == activity || TextUtils.isEmpty(permission)) {
return false;
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
int grand = ActivityCompat.checkSelfPermission(activity, permission);
if (grand != PermissionChecker.PERMISSION_GRANTED) {
return false;
}
return true;
} else {
return true;
}
}
/**
* 判断是否勾选禁止后不再询问
*
* @param activity
* @param permission
* @return
*/
public boolean shouldShowRequestPermission(Activity activity, String permission) {
if (null == activity || TextUtils.isEmpty(permission)) {
return false;
}
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
} else {
return true;
}
}
public PermissionUtil onCallback(PermissionCallback callback) {
this.permissionCallback = callback;
return this;
}
/**
* 回调接口
*/
public interface PermissionCallback {
void onGranted(List<String> actions);
void onDenied(List<String> actions);
}
/**
* 回调
*
* @param requestCode
* @param permissions
* @param grantResults
*/
public void onRequestPermissionsResult(int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
if (request_permission_code == requestCode) {
mHandler.post(new Runnable() {
@Override
public void run() {
List<String> g = new ArrayList<>(permissions.length);
List<String> d = new ArrayList<>(permissions.length);
for (int j = 0; j < grantResults.length; j++) {
final String p = permissions[j];
if (grantResults[j] == PackageManager.PERMISSION_GRANTED) {
g.add(p);
} else if (grantResults[j] == PackageManager.PERMISSION_DENIED) {
d.add(p);
}
}
if (null != permissionCallback) {
permissionCallback.onGranted(g);
permissionCallback.onDenied(d);
}
}
});
}
}
}
XML文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="76dp"
android:layout_marginLeft="76dp"
android:layout_marginTop="228dp"
android:text="详细地址:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="144dp"
android:layout_marginLeft="144dp"
android:layout_marginTop="228dp"
android:text="demo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="76dp"
android:layout_marginLeft="76dp"
android:layout_marginTop="172dp"
android:text="经纬度:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="132dp"
android:layout_marginLeft="132dp"
android:layout_marginTop="172dp"
android:text="demo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="76dp"
android:layout_marginLeft="76dp"
android:layout_marginTop="300dp"
android:text="获取经纬度和地址"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
三、调用百度地图SDK,显示当前定位
DemoApplication.java
import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
public class DemoApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//在使用SDK各组件之前初始化context信息,传入ApplicationContext
SDKInitializer.initialize(this);
//自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
//包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
SDKInitializer.setCoordType(CoordType.BD09LL);
}
}
MainActivity.java(加入百度地图后的代码)
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.PermissionUtils;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TextView textView2;
private TextView textView3;
private Button button;
private String address;
double latitude;
double longitude;
public LocationClient mLocationClient = null;
private MyLocationListener myListener = new MyLocationListener();
private boolean isFirstLocate = true;
private MapView mMapView = null;
private BaiduMap mBaiduMap;
//BDAbstractLocationListener为7.2版本新增的Abstract类型的监听接口
//原有BDLocationListener接口暂时同步保留。具体介绍请参考后文第四步的说明
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//权限检测和申请工具类
PermissionUtil.getInstance().onCallback(new PermissionUtil.PermissionCallback() {
@Override
public void onGranted(List<String> actions) {
for (String action : actions) {
Log.e("TAG", String.format("onGranted: %s", action));
}
}
@Override
public void onDenied(List<String> actions) {
for (String action : actions) {
Log.e("TAG", String.format("onGranted: %s", action));
}
}
}).requestPermissions(this, new String[]{
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.ACCESS_WIFI_STATE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.INTERNET
});
init();
initLocationClient();
setLocationClientOption();
mMapView = (MapView) findViewById(R.id.bmapView);
// 不显示缩放比例尺
mMapView.showZoomControls(false);
// 不显示百度地图Logo
mMapView.removeViewAt(1);
//百度地图
mBaiduMap = mMapView.getMap();
// 改变地图状态,使地图显示在恰当的缩放大小
MapStatus mMapStatus = new MapStatus.Builder().zoom(15).build();
MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
mBaiduMap.setMapStatus(mMapStatusUpdate);
//获取地图控件引用
mBaiduMap.setMyLocationEnabled(true);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLocationClient.start(); //开始定位
//mLocationClient为第二步初始化过的LocationClient对象
//调用LocationClient的start()方法,便可发起定位请求
}
});
}
//绑定组件
private void init(){
textView2 = findViewById(R.id.textView2);
textView3 = findViewById(R.id.textView3);
button = findViewById(R.id.button);
}
/**
* 初始化LocationClient类
* 请在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。
* 推荐使用getApplicationConext()方法获取全进程有效的Context。
*/
private void initLocationClient(){
//定位监听器,一旦调用requestLocation()函数,就会触发MyLocationListener()
mLocationClient = new LocationClient(getApplicationContext());
//声明LocationClient类
mLocationClient.registerLocationListener(myListener);
}
/**
* 配置定位SDK参数
* 通过参数配置,可选择定位模式、可设定返回经纬度坐标类型、可设定是单次定位还是连续定位。
* 定位SDK所提供的定位模式包括三种:高精度、低功耗和仅用设备定位。开发者请根据自己的实际使用需求进行选择。
*
* 定位SDK能够返回三种坐标类型的经纬度(国内),分别是GCJ02(国测局坐标)、BD09(百度墨卡托坐标)和BD09ll(百度经纬度坐标)。
* 如果开发者想利用定位SDK获得的经纬度直接在百度地图上标注,请选择坐标类型BD09ll。
*/
private void setLocationClientOption(){
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//可选,设置定位模式,默认高精度
//LocationMode.Hight_Accuracy:高精度;
//LocationMode. Battery_Saving:低功耗;
//LocationMode. Device_Sensors:仅使用设备;
option.setCoorType("bd09ll");
//可选,设置返回经纬度坐标类型,默认GCJ02
//GCJ02:国测局坐标;
//BD09ll:百度经纬度坐标;
//BD09:百度墨卡托坐标;
//海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标
option.setScanSpan(1000);
//可选,设置发起定位请求的间隔,int类型,单位ms
//如果设置为0,则代表单次定位,即仅定位一次,默认为0
//如果设置非0,需设置1000ms以上才有效
option.setOpenGps(true);
//可选,设置是否使用gps,默认false
//使用高精度和仅用设备两种定位模式的,参数必须设置为true
option.setLocationNotify(true);
//可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false
option.setIgnoreKillProcess(false);
//可选,定位SDK内部是一个service,并放到了独立进程。
//设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)
option.SetIgnoreCacheException(false);
//可选,设置是否收集Crash信息,默认收集,即参数为false
option.setWifiCacheTimeOut(5*60*1000);
//可选,V7.2版本新增能力
//如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位
option.setEnableSimulateGps(false);
//可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false
option.setNeedNewVersionRgc(true);
//可选,设置是否需要最新版本的地址信息。默认需要,即参数为true
option.setIsNeedAddress(true);
//可选,是否需要地址信息,默认为不需要,即参数为false
//如果开发者需要获得当前点的地址信息,此处必须为true
option.setNeedNewVersionRgc(true);
//可选,设置是否需要最新版本的地址信息。默认需要,即参数为true
mLocationClient.setLocOption(option);
//mLocationClient为第二步初始化过的LocationClient对象
//需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
//更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明
}
/**
* 实现BDAbstractLocationListener接口
* Android定位SDK自V7.2版本起,对外提供了Abstract类型的监听接口BDAbstractLocationListener,用于实现定位监听。
*/
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location){
//mapView 销毁后不在处理新接收的位置
if (location == null || mMapView == null){
return;
}
//此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
//以下只列举部分获取经纬度相关(常用)的结果信息
//更多结果信息获取说明,请参照类参考中BDLocation类中的说明
latitude = location.getLatitude(); //获取纬度信息
longitude = location.getLongitude(); //获取经度信息
float radius = location.getRadius(); //获取定位精度,默认值为0.0f
String coorType = location.getCoorType();
//获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
int errorCode = location.getLocType();
//获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
address = location.getAddrStr();
textView2.setText(longitude + ", " + latitude);
textView3.setText(address);
mLocationClient.stop();
//mapView 销毁后不在处理新接收的位置
if (location == null || mMapView == null){
return;
}
MyLocationData locData = new MyLocationData.Builder()
.accuracy(location.getRadius())
// 此处设置开发者获取到的方向信息,顺时针0-360
.direction(location.getDirection()).latitude(location.getLatitude())
.longitude(location.getLongitude()).build();
mBaiduMap.setMyLocationData(locData);
navigateTo(location);
}
}
/*移动到指定位置*/
private void navigateTo(BDLocation location){
LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(25f);
mBaiduMap.animateMapStatus(update);
MyLocationData.Builder locationBuilder =
new MyLocationData.Builder();
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData = locationBuilder.build();
mBaiduMap.setMyLocationData(locationData);
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
@Override
protected void onDestroy() {
mLocationClient.stop();
mBaiduMap.setMyLocationEnabled(false);
mMapView.onDestroy();
mMapView = null;
super.onDestroy();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mycourse4">
<!-- 这个权限用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="DemoApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="YourAK" >
</meta-data>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote"/>
</application>
</manifest>
四、添加和风天气SDK,显示当前位置天气
注册和风天气账号
在应用管理创建一个安卓SDK应用
DemoApplication.java
import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
import com.qweather.sdk.view.HeConfig;
public class DemoApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//在使用SDK各组件之前初始化context信息,传入ApplicationContext
SDKInitializer.initialize(this);
//自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
//包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
SDKInitializer.setCoordType(CoordType.BD09LL);
//和风天气
HeConfig.init("PublicId", "PrivateKey");
HeConfig.switchToDevService();
}
}
添加了和风天气安卓SDK后的MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.PermissionUtils;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;
import com.google.gson.Gson;
import com.qweather.sdk.bean.base.Code;
import com.qweather.sdk.bean.base.Lang;
import com.qweather.sdk.bean.base.Unit;
import com.qweather.sdk.bean.weather.WeatherNowBean;
import com.qweather.sdk.view.QWeather;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TextView textView2;
private TextView textView3;
private TextView textView6;
private Button button;
private Button button2;
private String address;
double latitude;
double longitude;
public LocationClient mLocationClient = null;
private MyLocationListener myListener = new MyLocationListener();
private boolean isFirstLocate = true;
private MapView mMapView = null;
private BaiduMap mBaiduMap;
//BDAbstractLocationListener为7.2版本新增的Abstract类型的监听接口
//原有BDLocationListener接口暂时同步保留。具体介绍请参考后文第四步的说明
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//权限检测和申请工具类
PermissionUtil.getInstance().onCallback(new PermissionUtil.PermissionCallback() {
@Override
public void onGranted(List<String> actions) {
for (String action : actions) {
Log.e("TAG", String.format("onGranted: %s", action));
}
}
@Override
public void onDenied(List<String> actions) {
for (String action : actions) {
Log.e("TAG", String.format("onGranted: %s", action));
}
}
}).requestPermissions(this, new String[]{
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.ACCESS_WIFI_STATE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.INTERNET
});
init();
initLocationClient();
setLocationClientOption();
mMapView = (MapView) findViewById(R.id.bmapView);
// 不显示缩放比例尺
mMapView.showZoomControls(false);
// 不显示百度地图Logo
mMapView.removeViewAt(1);
//百度地图
mBaiduMap = mMapView.getMap();
// 改变地图状态,使地图显示在恰当的缩放大小
MapStatus mMapStatus = new MapStatus.Builder().zoom(15).build();
MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
mBaiduMap.setMapStatus(mMapStatusUpdate);
//获取地图控件引用
mBaiduMap.setMyLocationEnabled(true);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mLocationClient.start(); //开始定位
//mLocationClient为第二步初始化过的LocationClient对象
//调用LocationClient的start()方法,便可发起定位请求
}
});
//和风天气
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 实况天气数据
* @param location 所查询的地区,可通过该地区名称、ID、IP和经纬度进行查询经纬度格式:经度,纬度
* (英文,分隔,十进制格式,北纬东经为正,南纬西经为负)
* @param lang (选填)多语言,可以不使用该参数,默认为简体中文
* @param unit (选填)单位选择,公制(m)或英制(i),默认为公制单位
* @param listener 网络访问结果回调
*/
QWeather.getWeatherNow(MainActivity.this, longitude+","+latitude, Lang.ZH_HANS, Unit.METRIC, new QWeather.OnResultWeatherNowListener() {
@Override
public void onError(Throwable e) {
Log.i("TAG", "getWeather onError: " + e);
}
@Override
public void onSuccess(WeatherNowBean weatherBean) {
Log.i("TAG", "getWeather onSuccess: " + new Gson().toJson(weatherBean));
//先判断返回的status是否正确,当status正确时获取数据,若status不正确,可查看status对应的Code值找到原因
if (Code.OK.getCode().equalsIgnoreCase(weatherBean.getCode())) {
WeatherNowBean.NowBaseBean now = weatherBean.getNow();
textView6.setText(now.getText()+" "+now.getTemp()+"ºC");
} else {
//在此查看返回数据失败的原因
String status = weatherBean.getCode();
Code code = Code.toEnum(status);
Log.i("TAG", "failed code: " + code);
}
}
});
}
});
}
//绑定组件
private void init(){
textView2 = findViewById(R.id.textView2);
textView3 = findViewById(R.id.textView3);
textView6 = findViewById(R.id.textView6);
button = findViewById(R.id.button);
button2 = findViewById(R.id.button2);
}
/**
* 初始化LocationClient类
* 请在主线程中声明LocationClient类对象,该对象初始化需传入Context类型参数。
* 推荐使用getApplicationConext()方法获取全进程有效的Context。
*/
private void initLocationClient(){
//定位监听器,一旦调用requestLocation()函数,就会触发MyLocationListener()
mLocationClient = new LocationClient(getApplicationContext());
//声明LocationClient类
mLocationClient.registerLocationListener(myListener);
}
/**
* 配置定位SDK参数
* 通过参数配置,可选择定位模式、可设定返回经纬度坐标类型、可设定是单次定位还是连续定位。
* 定位SDK所提供的定位模式包括三种:高精度、低功耗和仅用设备定位。开发者请根据自己的实际使用需求进行选择。
*
* 定位SDK能够返回三种坐标类型的经纬度(国内),分别是GCJ02(国测局坐标)、BD09(百度墨卡托坐标)和BD09ll(百度经纬度坐标)。
* 如果开发者想利用定位SDK获得的经纬度直接在百度地图上标注,请选择坐标类型BD09ll。
*/
private void setLocationClientOption(){
LocationClientOption option = new LocationClientOption();
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//可选,设置定位模式,默认高精度
//LocationMode.Hight_Accuracy:高精度;
//LocationMode. Battery_Saving:低功耗;
//LocationMode. Device_Sensors:仅使用设备;
option.setCoorType("bd09ll");
//可选,设置返回经纬度坐标类型,默认GCJ02
//GCJ02:国测局坐标;
//BD09ll:百度经纬度坐标;
//BD09:百度墨卡托坐标;
//海外地区定位,无需设置坐标类型,统一返回WGS84类型坐标
option.setScanSpan(1000);
//可选,设置发起定位请求的间隔,int类型,单位ms
//如果设置为0,则代表单次定位,即仅定位一次,默认为0
//如果设置非0,需设置1000ms以上才有效
option.setOpenGps(true);
//可选,设置是否使用gps,默认false
//使用高精度和仅用设备两种定位模式的,参数必须设置为true
option.setLocationNotify(true);
//可选,设置是否当GPS有效时按照1S/1次频率输出GPS结果,默认false
option.setIgnoreKillProcess(false);
//可选,定位SDK内部是一个service,并放到了独立进程。
//设置是否在stop的时候杀死这个进程,默认(建议)不杀死,即setIgnoreKillProcess(true)
option.SetIgnoreCacheException(false);
//可选,设置是否收集Crash信息,默认收集,即参数为false
option.setWifiCacheTimeOut(5*60*1000);
//可选,V7.2版本新增能力
//如果设置了该接口,首次启动定位时,会先判断当前Wi-Fi是否超出有效期,若超出有效期,会先重新扫描Wi-Fi,然后定位
option.setEnableSimulateGps(false);
//可选,设置是否需要过滤GPS仿真结果,默认需要,即参数为false
option.setNeedNewVersionRgc(true);
//可选,设置是否需要最新版本的地址信息。默认需要,即参数为true
option.setIsNeedAddress(true);
//可选,是否需要地址信息,默认为不需要,即参数为false
//如果开发者需要获得当前点的地址信息,此处必须为true
option.setNeedNewVersionRgc(true);
//可选,设置是否需要最新版本的地址信息。默认需要,即参数为true
mLocationClient.setLocOption(option);
//mLocationClient为第二步初始化过的LocationClient对象
//需将配置好的LocationClientOption对象,通过setLocOption方法传递给LocationClient对象使用
//更多LocationClientOption的配置,请参照类参考中LocationClientOption类的详细说明
}
/**
* 实现BDAbstractLocationListener接口
* Android定位SDK自V7.2版本起,对外提供了Abstract类型的监听接口BDAbstractLocationListener,用于实现定位监听。
*/
public class MyLocationListener extends BDAbstractLocationListener {
@Override
public void onReceiveLocation(BDLocation location){
//mapView 销毁后不在处理新接收的位置
if (location == null || mMapView == null){
return;
}
//此处的BDLocation为定位结果信息类,通过它的各种get方法可获取定位相关的全部结果
//以下只列举部分获取经纬度相关(常用)的结果信息
//更多结果信息获取说明,请参照类参考中BDLocation类中的说明
latitude = location.getLatitude(); //获取纬度信息
longitude = location.getLongitude(); //获取经度信息
float radius = location.getRadius(); //获取定位精度,默认值为0.0f
String coorType = location.getCoorType();
//获取经纬度坐标类型,以LocationClientOption中设置过的坐标类型为准
int errorCode = location.getLocType();
//获取定位类型、定位错误返回码,具体信息可参照类参考中BDLocation类中的说明
address = location.getAddrStr();
textView2.setText(longitude + ", " + latitude);
textView3.setText(address);
mLocationClient.stop();
//mapView 销毁后不在处理新接收的位置
if (location == null || mMapView == null){
return;
}
MyLocationData locData = new MyLocationData.Builder()
.accuracy(location.getRadius())
// 此处设置开发者获取到的方向信息,顺时针0-360
.direction(location.getDirection()).latitude(location.getLatitude())
.longitude(location.getLongitude()).build();
mBaiduMap.setMyLocationData(locData);
navigateTo(location);
}
}
/*移动到指定位置*/
private void navigateTo(BDLocation location){
LatLng ll = new LatLng(location.getLatitude(),location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
mBaiduMap.animateMapStatus(update);
update = MapStatusUpdateFactory.zoomTo(25f);
mBaiduMap.animateMapStatus(update);
MyLocationData.Builder locationBuilder =
new MyLocationData.Builder();
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData = locationBuilder.build();
mBaiduMap.setMyLocationData(locationData);
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
mMapView.onPause();
}
@Override
protected void onDestroy() {
mLocationClient.stop();
mBaiduMap.setMyLocationEnabled(false);
mMapView.onDestroy();
mMapView = null;
super.onDestroy();
//在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
}
}
bulid.gradle
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation files('libs\\BaiduLBS_Android.jar')
implementation files('libs\\QWeather_Public_Android_V4.2.jar')
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.squareup.okhttp3:okhttp:4.3.0'
implementation 'com.google.code.gson:gson:2.8.6'
}
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="36dp"
android:text="详细地址:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="92dp"
android:layout_marginLeft="92dp"
android:layout_marginTop="36dp"
android:text="demo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="16dp"
android:text="经纬度:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="76dp"
android:layout_marginLeft="76dp"
android:layout_marginTop="16dp"
android:text="demo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="361dp"
android:layout_marginTop="68dp"
android:clickable="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="440dp"
android:text="获取经纬度和地址并定位"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="28dp"
android:layout_marginLeft="28dp"
android:layout_marginTop="28dp"
android:text="当前位置天气:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="28dp"
android:layout_marginLeft="28dp"
android:layout_marginTop="544dp"
android:text="获取天气信息"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="128dp"
android:layout_marginLeft="128dp"
android:layout_marginTop="516dp"
android:text="TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
SDK
所有的SDK和so文件都在上面的百度网盘链接里,jar文件放在libs里面,记得右键add as Library。so文件放在jniLibs下对应文件夹下。
项目结构