文章说明:本文初衷是为了记录毕设学习过程,避免忘记操作流程。该功能是毕业设计的Android软件端的功能之一,本文将从获取百度地图密钥(AK)开始,详细地对地图定位配置和相关代码进行说明,文末将附上实现该功能的代码。后续等答辩完成会把整个Android端代码上传。
6月27日更新,完整的智能家居APP的源码和相关说明已经发出,感兴趣的同学点开链接看看
使用Android studio完成简易智能家居APP的制作(含源码工程包)
目录
1、使用的软硬件说明
1)获取包名
2)获取SHA1(重点)
3、下载相关开发包并将文件配置到Android studio的文件中
1、Android SDK专业解释:
2、Android SDK的获取
3、下载相关开发包后,进行Android Studio的配置
1、将获取的百度地图移动版开发密钥AK,配置到Android studio中
2、将下载好的JAR格式百度地图开发包置于libs下,并在build.gradle中增加一条语句,用于展开JAR开发包
3、创建一个jniLibs文件名,在src/java/jniLibs这个路径下,添加开发包的其他文件
4、在activity_main.xml的layout文件中,设置相关按钮(就是普通/卫星地图那些玩意的选择)
5、开启权限(定位权限,网络权限等)
4、代码(地图定位)
在进入学习前,老(新)规矩,先看效果图:
2023/4.8 新增功能及其界面如下:
okok,看完效果图,那咱们就开始吧!
软件:百度地图API,使用的外部包是百度地图Android SDK基于Android 4.0及以上版本设备的应用程序接口,Android studio开发软件,360手机助手。
硬件:openA57手机一台,数据线一根
百度地图移动版的开发密钥(AK)是一个API访问授权凭证,用于验证应用程序或网站请求百度地图API时的身份和权限。它是一段由百度地图开发者平台生成的字符串,类似于密码,需要在每次API调用中传递给服务器以获得访问权限。
具体步骤如下:
1、登录或者注册百度地图开放平台,进入链接获取百度地图开发密钥网址链接
2、点击创建应用
3、进入界面后,选择Android SDK,自己创建应用名字
4、这一步涉及到两个关键的信息源,如何获得这两个信息显得十分的关键,这两个信息分别是包名和SHA1,如图所示,其中发布饭SHA1和包名是必填项,具体如何获取,下面我将详细说明。当然也可以通过官方获取文档的教学进行操作获取。
首先说明一下SHA1其实是
SHA1 (Secure Hash Algorithm 1) 是一种加密算法,常用于验证数据的完整性和安全性。在地图开发中,获取SHA1通常是为了使用百度地图服务API进行身份验证和授权。通常需要生成应用程序签名并使用keytool工具来获取SHA1指纹。
那么具体应该如何操作呢?
此处教一个万能的方法,首先打开安装Android studio目录下的jre,此处我安装的路径是C:\Program Files\Android\Android Studio\jre\bin;找到路径后,使用win+R输入cmd命令,进入命令行工具(或者直接右键点击在终端打开)如下图所示:
然后找到你的 debug.keystore所在的目录,如图所示,我的在c盘用户目录的.android一般都在这个“.android”目录下,这个需要自己寻找哈!完成这一步,恭喜你,你已经近乎完成了!!!
还记得我们刚刚打开的cmd命令端吗?打开它然后直接输入下面这串字符和刚刚找到的debug.keystore路径,再之后回车即可:
keytool -list -v -keystore 路径(刚刚寻找的debug.keystore的路径)
需要注意的是,它需要你输入密钥库口令,请输入:android
如图所示,你成功获得了SHA1数据;接下来在创建应用界面输入包名和SHA1的数据即可,让后你就得到了一个应用,具体如下图,应用ak即可得到
这里呢,就需要我们下载一个Android SDK,这是个什么呢?且看解释!
Android SDK是指Android软件开发工具包(Software Development Kit),它是一组用于开发Android应用程序的工具和资源集合。Android SDK由Google或其他地图进行提供,可以免费下载和使用。
Android SDK包含了许多开发应用程序所需的组件,例如:
使用Android SDK,开发人员可以利用Java语言编写Android应用程序,并通过Eclipse、Android Studio等开发环境对其进行编辑、编译和打包等操作。同时,Android SDK还支持用C/C++语言编写Android应用程序,并利用NDK(Native Development Kit)进行编译等操作。
SDK下载 - 百度LBS开放平台
又将如何选择呢?我要完成的功能是地图和定位,故而选择的是①基础定位+②JAR格式包+③标准开发包,如图:
这里的配置较为繁琐,仔细点哇!
打开AndroidManifest.xml文件,在文件中进行如下图所示的配置:注意蓝牙框框内的name不允许改变,而那个value就是我们前边费劲心思搞到的ak
语句:implementation files('libs/BaiduLBS_Android.jar'),注意这条语句放在dependencies
什么?你说找不到libs包?找不到不会自己创建啊?嗯?
你问我为什么要取这么个名字(jniLibs)?我也不知道,真不知道,我去问问ChatGPT。看图,懂了吧!嘿嘿!
代码如下:
具体开启权限的代码如下(注意这里的开启的权限,一部分与地图定位的无关,这是因为开发的功能不仅仅局限于地图定位,懂?):
okok,通过上述五步,地图定位的配置工作已经告一段落了,接下来就是枯燥的代码环节,我将贴粗关键代码,仅供学习!说明:代码实际是借鉴一位大佬的,具体是谁,忘记了,我只是进行了一些简单的修改,而且改的很烂,反正你也打不到我,别在评论区骂我就行!
关于该功能实现的layout文件和权限配置这两个,我已经把代码贴出来了,往上找!
1、AndroidManifest.xml文件
首先需要声明,有些代码是不需要的,如下图的几个红色的框框,表示的是将要运行的Java活动程序,而该功能只需要执行MapApp、MainActivity两个Java活动程序。
我已经将不会用到的代码删除,具体如下:
2、在进活动运行前,还需要运行一个,MapApp.java文件
用于动态申请啥的...
package com.example.lbstest;
import android.app.Application;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
public class MapApp extends Application {
@Override
public void onCreate() {
super.onCreate();
//动态申请
SDKInitializer.setAgreePrivacy(this,true);
//在使用SDK各组件之前初始化context信息,传入ApplicationContext
SDKInitializer.initialize(this);
//自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
//包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
SDKInitializer.setCoordType(CoordType.BD09LL);
}
}
3、下面就是核心代码,MainActivity.java文件
package com.example.lbstest;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import com.baidu.mapapi.map.MapView;
public class MainActivity extends AppCompatActivity{//MainActivity类继承于AppCompatActivity类
/*
以下MAP中用到到参数
* */
private MapView mMapView;
private RadioGroup mapType;
private RadioButton nombtn;
private RadioButton sabtn;
private CheckBox lubtn;
private CheckBox rebtn;
private com.baidu.location.LocationClient mLocClient;
private com.baidu.mapapi.map.BaiduMap mBaiduMap;
private com.baidu.mapapi.map.BitmapDescriptor bitmap;//标点的图标
private double markerLatitude = 0;//标点纬度
private double markerLongitude = 0;//标点经度
private ImageButton ibLocation;//重置定位按钮
private com.baidu.mapapi.map.Marker marker;//标点也可以说是覆盖物
public int MAP_flag =0;//用于点击按钮后是否在家附近
public static final String TAG="RightFragment";
@SuppressLint({"MissingInflatedId", "ResourceType"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.bmapView);
mapType = findViewById(R.id.id_rp_mapType);
nombtn = findViewById(R.id.id_normal);
sabtn = findViewById(R.id.id_satel);
lubtn= findViewById(R.id.id_lukuan);
rebtn=findViewById(R.id.id_reli);
initEvent();
initView();//视图初始化
initLocation();//定位初始化
mapOnClick();//地图点击
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.bluetooth_map_onenet, menu);
return true;
}
/**
* 绑定Options Menu的事件
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemid = item.getItemId();// 获取当前点击菜单的资源ID
/* 新建一个Intent对象 */
Intent intent = new Intent();
switch (itemid){
case R.id.action_bluetooth_button:
/* 指定intent要启动的类 */
intent.setClass(MainActivity.this, BlueToothActivity.class);
/* 启动一个新的Activity */
startActivity(intent);
/* 关闭当前的Activity */
MainActivity.this.finish();
break;
case R.id.action_baidu_map:
Toast.makeText(this, "你正在此界面", Toast.LENGTH_LONG).show();
case R.id.action_onenet_button:
/* 指定intent要启动的类 */
intent.setClass(MainActivity.this, OneNetActivity.class);
/* 启动一个新的Activity */
startActivity(intent);
/* 关闭当前的Activity */
MainActivity.this.finish();
break;
}
return super.onOptionsItemSelected(item);
}
/**
* 事件处理初始化
*/
private void initEvent(){
mapType.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {//地图类型选择
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
if (i==nombtn.getId()){
mMapView.getMap().setMapType(com.baidu.mapapi.map.BaiduMap.MAP_TYPE_NORMAL);//普通地图
}else if (i==sabtn.getId()){
mMapView.getMap().setMapType(com.baidu.mapapi.map.BaiduMap.MAP_TYPE_SATELLITE);//卫星地图
//
}
}
});
lubtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mMapView.getMap().setTrafficEnabled(b);//调用路况图
}
});
rebtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mMapView.getMap().setBaiduHeatMapEnabled(b);//调用热力图
}
});
}
private void initView() {
// 地图初始化
mMapView = (MapView) findViewById(R.id.bmapView);
//回到当前定位
ibLocation = (ImageButton) findViewById(R.id.ib_location);
mMapView.showScaleControl(false); // 设置比例尺是否可见(true 可见/false不可见)
//mMapView.showZoomControls(false); // 设置缩放控件是否可见(true 可见/false不可见)
mMapView.removeViewAt(1);// 删除百度地图Logo
mBaiduMap = mMapView.getMap();
mBaiduMap.setOnMarkerClickListener(new com.baidu.mapapi.map.BaiduMap.OnMarkerClickListener() {//地图的点击事件
@Override
public boolean onMarkerClick(com.baidu.mapapi.map.Marker marker) {
final String info = (String) marker.getExtraInfo().get("info");
Toast.makeText(MainActivity.this, info, Toast.LENGTH_SHORT).show();
return true;
}
});
}
/**
* 定位初始化
*/
public void initLocation() {
//添加隐私合规政策
com.baidu.location.LocationClient.setAgreePrivacy(true);
// 开启定位图层
mBaiduMap.setMyLocationEnabled(true);
// 定位初始化
if (mLocClient == null) {
try {
mLocClient = new com.baidu.location.LocationClient(this);
} catch (Exception e) {
e.printStackTrace();
}
}
if (mLocClient != null) {
MyLocationListener myListener = new MyLocationListener();
mLocClient.registerLocationListener(myListener);
com.baidu.location.LocationClientOption option = new com.baidu.location.LocationClientOption();
option.setLocationMode(com.baidu.location.LocationClientOption.LocationMode.Hight_Accuracy);// 设置高精度定位
option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系,bd09ll 百度经纬度坐标
option.setScanSpan(0);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
option.setIgnoreKillProcess(false);//可选,默认false,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认杀死
option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集
mLocClient.setLocOption(option);
mLocClient.start();//开始定位
}
}
/**
* 点切换到其他标点位置时,重置定位显示,点击之后回到自动定位
*
* @param view
*/
public void resetLocation(View view) {
markerLatitude = 0;
initLocation();
marker.remove();//清除标点
}
/**
* 地图点击事件处理
*/
public void mapOnClick() {
// 设置marker图标
bitmap = com.baidu.mapapi.map.BitmapDescriptorFactory.fromResource(R.drawable.icon_marka);
mBaiduMap.setOnMapClickListener(new com.baidu.mapapi.map.BaiduMap.OnMapClickListener() {
@Override
public void onMapPoiClick(com.baidu.mapapi.map.MapPoi mapPoi) {
}
//此方法就是点击地图监听
@Override
public void onMapClick(com.baidu.mapapi.model.LatLng latLng) {
//获取经纬度
markerLatitude = latLng.latitude;
markerLongitude = latLng.longitude;
//先清除图层
mBaiduMap.clear();
// 定义Maker坐标点
com.baidu.mapapi.model.LatLng point = new com.baidu.mapapi.model.LatLng(markerLatitude, markerLongitude);
// 构建MarkerOption,用于在地图上添加Marker
com.baidu.mapapi.map.MarkerOptions options = new com.baidu.mapapi.map.MarkerOptions().position(point)
.icon(bitmap);
// 在地图上添加Marker,并显示
//mBaiduMap.addOverlay(options);
marker = (com.baidu.mapapi.map.Marker) mBaiduMap.addOverlay(options);
Bundle bundle = new Bundle();
bundle.putSerializable("info", "纬度:" + markerLatitude + " 经度:" + markerLongitude);
marker.setExtraInfo(bundle);//将bundle值传入marker中,给baiduMap设置监听时可以得到它
/**
*这个是弹窗的提醒,当定位到家附近时,将提醒转跳远端控制OneNetActivity
* */
if (markerLatitude >= 23.72 && markerLongitude >=113.08 && markerLatitude <= 23.73 && markerLongitude <=113.09) {
AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this)
.setTitle("转跳远端控制")
.setMessage("此时已经定位至家的附近,是否转跳远端控制")
.setIcon(R.mipmap.ic_launcher)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {//添加"Yes"按钮
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent_DW = new Intent();//转跳活动
/* 指定intent要启动的类 */
intent_DW.setClass(MainActivity.this, OneNetActivity.class);
/* 启动一个新的Activity */
startActivity(intent_DW);
/* 关闭当前的Activity */
MainActivity.this.finish();
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {//添加取消
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(MainActivity.this, "好的,收到主人", Toast.LENGTH_SHORT).show();
}
}).create();
alertDialog.show();
}
System.out.println("纬度"+markerLatitude);
System.out.println("经度"+markerLongitude);
System.out.println("标记位"+MAP_flag);
//点击地图之后重新定位
initLocation();
}
});
}
/**
* 定位SDK监听函数
*/
public class MyLocationListener extends com.baidu.location.BDAbstractLocationListener {
@Override
public void onReceiveLocation(com.baidu.location.BDLocation location){
Toast.makeText(MainActivity.this, location.getAddrStr(), Toast.LENGTH_SHORT).show();
// MapView 销毁后不在处理新接收的位置
if (mMapView == null) {
return;
}
double resultLatitude;
double resultLongitude;
if (markerLatitude == 0) {//自动定位
resultLatitude = location.getLatitude();
resultLongitude = location.getLongitude();
ibLocation.setVisibility(View.GONE);
} else {//标点定位
resultLatitude = markerLatitude;
resultLongitude = markerLongitude;
ibLocation.setVisibility(View.VISIBLE);
}
com.baidu.mapapi.map.MyLocationData locData = new com.baidu.mapapi.map.MyLocationData.Builder()
.accuracy(location.getRadius())// 设置定位数据的精度信息,单位:米
.direction(location.getDirection()) // 此处设置开发者获取到的方向信息,顺时针0-360
.latitude(resultLatitude)
.longitude(resultLongitude)
.build();
mBaiduMap.setMyLocationData(locData);// 设置定位数据, 只有先允许定位图层后设置数据才会生效
com.baidu.mapapi.model.LatLng latLng = new com.baidu.mapapi.model.LatLng(resultLatitude, resultLongitude);
com.baidu.mapapi.map.MapStatus.Builder builder = new com.baidu.mapapi.map.MapStatus.Builder();
builder.target(latLng).zoom(20.0f);
mBaiduMap.animateMapStatus(com.baidu.mapapi.map.MapStatusUpdateFactory.newMapStatus(builder.build()));
}
}
@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() {
super.onDestroy();
// 退出时销毁定位
mLocClient.stop();
// 关闭定位图层
mBaiduMap.setMyLocationEnabled(false);
// 在activity执行onDestroy时必须调用mMapView.onDestroy()
mMapView.onDestroy();
}
}
行了,打完收工!
回头答完辩,把工程代码贴出来,再会!
使用三道不那么华丽的水平线,以下是更新后的代码,为了使代码的可用性和把玩性更高,我将一开始写死在代码里的经纬度数据进行了修正用以保证我项目的完整性。
项目需求:当在地图界面点击设置按钮后,界面有三个输入的EditText,分别是输入家庭地址、输入经度、输入纬度,需要注意的是只要提供家庭地址,就会自动生成经纬度,相反,只要提供经纬度,就会自动定位出家庭地址,并显示到文本框。除此之外还提供三个按钮,其一是清空当前输入数据,注意清空的数据是EditText中的数据;其二是获取当前位置,直接设置为家庭地址,需要注意的是,此时只是显示在EditText中,真正的参数并不赋值;最后一个按钮功能是设置完成,返回地图界面,需要注意的是,返回的同时,需要把经纬度两个参数进行赋值。
修改后的MainActivity代码:
package com.example.lbstest;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import com.baidu.mapapi.map.MapView;
import java.text.DecimalFormat;
public class MainActivity extends AppCompatActivity{//MainActivity类继承于AppCompatActivity类
/*
以下MAP中用到到参数
* */
private MapView mMapView;
private RadioGroup mapType;
private RadioButton nombtn;//普通地图
private RadioButton sabtn;//卫星地图
private CheckBox lubtn;//路况图选择
private CheckBox rebtn;//热力图选择
private Button setButton_Home;//设置家庭地址按钮
private com.baidu.location.LocationClient mLocClient;
private com.baidu.mapapi.map.BaiduMap mBaiduMap;
private com.baidu.mapapi.map.BitmapDescriptor bitmap;//标点的图标
private double markerLatitude = 0;//标点纬度
private double markerLongitude = 0;//标点经度
private ImageButton ibLocation;//重置定位按钮
private com.baidu.mapapi.map.Marker marker;//标点也可以说是覆盖物
//标记位
public int SetHomeLocation_Flg = 0;//代码是否设置成功
/**
* 参数说明:对家庭地址的经纬度进行设置,初始为广东省清远市清城区清辉北路,
* 我要通过设置按钮传递到SetHomeLocationActivity活动里,因为它是默认的地址
*/
private double latitude = 23.72;
private double longitude = 113.08;//经纬度初始是清远的地址调用对应的destroy()方法释放资源
/**
* 设置全局变量的经纬度
*/
public double Longitude;
public double Latitude;
public static final String TAG="RightFragment";
@SuppressLint({"MissingInflatedId", "ResourceType"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 作者:唐瑛琪
* 日期:2023年4月7日
* 邮箱:[email protected]
* 参数(判断)说明:通过设置的地址按钮,触发SetHomeLocationActivity活动,
* 并把在此活动中设置的经纬度传回MainActivity活动,
* 并在点击定位出调用,注意,如果使用默认的地址,也需要进行设置。
* 接受MainActivity活动的数据,并将传入的double数据只取小数点两位数据。我的需求就是,不太准确的经纬度
*/
SetHomeLocation_Flg = getIntent().getIntExtra("Set_home_flg",0);
if(SetHomeLocation_Flg == 1) {
Longitude = getIntent().getDoubleExtra("Longitude", 0);
Latitude = getIntent().getDoubleExtra("Latitude", 0);
/*以下测试数据*/
// System.out.println("经度"+Longitude);
// System.out.println("纬度"+Latitude);
//将double类型的经纬度保留小数点后两位,我不需要过于精确的数据
DecimalFormat df = new DecimalFormat("#.00");
String LongitudeFormatted = df.format(Longitude);
String LatitudeFormatted = df.format(Latitude);
Longitude = Double.parseDouble(LongitudeFormatted);//将只剩下两个小数点的经纬度重新转化为double类型的数据
Latitude = Double.parseDouble(LatitudeFormatted);
SetHomeLocation_Flg = 0;//设置完成,标记位清零
/*以下测试数据*/
// Toast.makeText(this, "地址设置成功", Toast.LENGTH_LONG).show();
// System.out.println("保留两位小数的经度"+Longitude);
// System.out.println("保留两位小数的纬度"+Latitude);
}else if( SetHomeLocation_Flg==0 ){//两处赋值,一处是初始值,一处是SetHomeLocationActivity活动返回值
/**
* 作者:唐瑛琪
* 日期:2023年4月8日改
* 邮箱:[email protected]
* bug修复:如果直接返回地图不进行设置,则没有任何数据返回,以至于导致转跳远端控制弹窗不能用。
* 这样若不小心触发设置按钮,直接返回的的话,将没有经纬度数据,这里直接赋值为默认地址,以确保数据可用性
*/
Longitude = longitude;
Latitude = latitude;//使用默认的清远地址
Toast.makeText(this, "恢复默认家庭地址设置", Toast.LENGTH_LONG).show();
}
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.bmapView);
mapType = findViewById(R.id.id_rp_mapType);
nombtn = findViewById(R.id.id_normal);
sabtn = findViewById(R.id.id_satel);
lubtn = findViewById(R.id.id_lukuan);
rebtn =findViewById(R.id.id_reli);
setButton_Home = findViewById(R.id.id_set_home_location);//设置家庭地址的按钮
initEvent();
initView();//视图初始化
initLocation();//定位初始化
mapOnClick();//地图点击
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.bluetooth_map_onenet, menu);
return true;
}
/**
* 作者:唐瑛琪
* 邮箱:[email protected]
* 绑定Options Menu的事件
* 功能:用于配合菜单按钮的转跳功能,即重启一个新的活动
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemid = item.getItemId();// 获取当前点击菜单的资源ID
/* 新建一个Intent对象 */
Intent intent = new Intent();
switch (itemid){
case R.id.action_bluetooth_button:
/* 指定intent要启动的类 */
intent.setClass(MainActivity.this, BlueToothActivity.class);
/* 启动一个新的Activity */
startActivity(intent);
/* 关闭当前的Activity */
MainActivity.this.finish();
break;
case R.id.action_baidu_map:
Toast.makeText(this, "你正在此界面", Toast.LENGTH_LONG).show();
case R.id.action_onenet_button:
/* 指定intent要启动的类 */
intent.setClass(MainActivity.this, OneNetActivity.class);
/* 启动一个新的Activity */
startActivity(intent);
/* 关闭当前的Activity */
MainActivity.this.finish();
break;
}
return super.onOptionsItemSelected(item);
}
/**
* 事件处理初始化
*/
private void initEvent(){
mapType.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {//地图类型选择
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
if (i==nombtn.getId()){
mMapView.getMap().setMapType(com.baidu.mapapi.map.BaiduMap.MAP_TYPE_NORMAL);//普通地图
}else if (i==sabtn.getId()){
mMapView.getMap().setMapType(com.baidu.mapapi.map.BaiduMap.MAP_TYPE_SATELLITE);//卫星地图
}
}
});
lubtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mMapView.getMap().setTrafficEnabled(b);//调用路况图
}
});
rebtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mMapView.getMap().setBaiduHeatMapEnabled(b);//调用热力图
}
});
setButton_Home.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SetHomeLocationActivity.class);
// 获取EditText中的经度和纬度
intent.putExtra("longitude", longitude);
intent.putExtra("latitude", latitude);
startActivity(intent);
}
});
}
private void initView() {
// 地图初始化
mMapView = (MapView) findViewById(R.id.bmapView);
//回到当前定位
ibLocation = (ImageButton) findViewById(R.id.ib_location);
mMapView.showScaleControl(false); // 设置比例尺是否可见(true 可见/false不可见)
//mMapView.showZoomControls(false); // 设置缩放控件是否可见(true 可见/false不可见)
mMapView.removeViewAt(1);// 删除百度地图Logo
mBaiduMap = mMapView.getMap();
mBaiduMap.setOnMarkerClickListener(new com.baidu.mapapi.map.BaiduMap.OnMarkerClickListener() {//地图的点击事件
@Override
public boolean onMarkerClick(com.baidu.mapapi.map.Marker marker) {
final String info = (String) marker.getExtraInfo().get("info");
Toast.makeText(MainActivity.this, info, Toast.LENGTH_SHORT).show();
return true;
}
});
}
/**
* 定位初始化
*/
public void initLocation() {
//添加隐私合规政策
com.baidu.location.LocationClient.setAgreePrivacy(true);
// 开启定位图层
mBaiduMap.setMyLocationEnabled(true);
// 定位初始化
if (mLocClient == null) {
try {
mLocClient = new com.baidu.location.LocationClient(this);
} catch (Exception e) {
e.printStackTrace();
}
}
if (mLocClient != null) {
MyLocationListener myListener = new MyLocationListener();
mLocClient.registerLocationListener(myListener);
com.baidu.location.LocationClientOption option = new com.baidu.location.LocationClientOption();
option.setLocationMode(com.baidu.location.LocationClientOption.LocationMode.Hight_Accuracy);// 设置高精度定位
option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系,bd09ll 百度经纬度坐标
option.setScanSpan(0);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要
option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
option.setIgnoreKillProcess(false);//可选,默认false,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认杀死
option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集
mLocClient.setLocOption(option);
mLocClient.start();//开始定位
}
}
/**
* 点切换到其他标点位置时,重置定位显示,点击之后回到自动定位
*
* @param view
*/
public void resetLocation(View view) {
markerLatitude = 0;
initLocation();
marker.remove();//清除标点
}
/**
* 地图点击事件处理
*/
public void mapOnClick() {
// 设置marker图标
bitmap = com.baidu.mapapi.map.BitmapDescriptorFactory.fromResource(R.drawable.icon_marka);
mBaiduMap.setOnMapClickListener(new com.baidu.mapapi.map.BaiduMap.OnMapClickListener() {
@Override
public void onMapPoiClick(com.baidu.mapapi.map.MapPoi mapPoi) {
}
//此方法就是点击地图监听
@Override
public void onMapClick(com.baidu.mapapi.model.LatLng latLng) {
//获取经纬度
markerLatitude = latLng.latitude;
markerLongitude = latLng.longitude;
//先清除图层
mBaiduMap.clear();
// 定义Maker坐标点
com.baidu.mapapi.model.LatLng point = new com.baidu.mapapi.model.LatLng(markerLatitude, markerLongitude);
// 构建MarkerOption,用于在地图上添加Marker
com.baidu.mapapi.map.MarkerOptions options = new com.baidu.mapapi.map.MarkerOptions().position(point)
.icon(bitmap);
// 在地图上添加Marker,并显示
//mBaiduMap.addOverlay(options);
marker = (com.baidu.mapapi.map.Marker) mBaiduMap.addOverlay(options);
Bundle bundle = new Bundle();
bundle.putSerializable("info", "纬度:" + markerLatitude + " 经度:" + markerLongitude);
marker.setExtraInfo(bundle);//将bundle值传入marker中,给baiduMap设置监听时可以得到它
/**
* 作者:唐瑛琪
* 邮箱:[email protected]
* 这个是弹窗的提醒,当定位到家附近时,将提醒转跳远端控制OneNetActivity。
* 所谓在家附件,就是大概经纬度地址,我的解决方案是设定一个区间,精度在0.1之间,可以大致确定一个区块。
* 当然,若读者能够有其他更好的解决方法,可以邮箱私信一起探讨
* */
if (markerLatitude >= (Latitude-0.01) && markerLongitude >=(Longitude-0.01) && markerLatitude <= (Latitude+0.01) && markerLongitude <=(Longitude+0.01)) {
AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this)
.setTitle("转跳远端控制")
.setMessage("此时已经定位至家的附近,是否转跳远端控制")
.setIcon(R.mipmap.ic_launcher)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {//添加"Yes"按钮
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent_DW = new Intent();//转跳活动
/* 指定intent要启动的类 */
intent_DW.setClass(MainActivity.this, OneNetActivity.class);
/* 启动一个新的Activity */
startActivity(intent_DW);
/* 关闭当前的Activity */
MainActivity.this.finish();
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {//添加取消
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast.makeText(MainActivity.this, "好的,收到主人", Toast.LENGTH_SHORT).show();
}
}).create();
alertDialog.show();
}
//点击地图之后重新定位
initLocation();
}
});
}
/**
* 定位SDK监听函数
*/
public class MyLocationListener extends com.baidu.location.BDAbstractLocationListener {
@Override
public void onReceiveLocation(com.baidu.location.BDLocation location){
Toast.makeText(MainActivity.this, location.getAddrStr(), Toast.LENGTH_SHORT).show();
// MapView 销毁后不在处理新接收的位置
if (mMapView == null) {
return;
}
double resultLatitude;
double resultLongitude;
if (markerLatitude == 0) {//自动定位
resultLatitude = location.getLatitude();
resultLongitude = location.getLongitude();
ibLocation.setVisibility(View.GONE);
} else {//标点定位
resultLatitude = markerLatitude;
resultLongitude = markerLongitude;
ibLocation.setVisibility(View.VISIBLE);
}
com.baidu.mapapi.map.MyLocationData locData = new com.baidu.mapapi.map.MyLocationData.Builder()
.accuracy(location.getRadius())// 设置定位数据的精度信息,单位:米
.direction(location.getDirection()) // 此处设置开发者获取到的方向信息,顺时针0-360
.latitude(resultLatitude)
.longitude(resultLongitude)
.build();
mBaiduMap.setMyLocationData(locData);// 设置定位数据, 只有先允许定位图层后设置数据才会生效
com.baidu.mapapi.model.LatLng latLng = new com.baidu.mapapi.model.LatLng(resultLatitude, resultLongitude);
com.baidu.mapapi.map.MapStatus.Builder builder = new com.baidu.mapapi.map.MapStatus.Builder();
builder.target(latLng).zoom(20.0f);
mBaiduMap.animateMapStatus(com.baidu.mapapi.map.MapStatusUpdateFactory.newMapStatus(builder.build()));
}
}
@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() {
super.onDestroy();
// 退出时销毁定位
mLocClient.stop();
// 关闭定位图层
mBaiduMap.setMyLocationEnabled(false);
// 在activity执行onDestroy时必须调用mMapView.onDestroy()
mMapView.onDestroy();
}
}
新增加的设置地址活动——SetHomeLocationActivity代码:
package com.example.lbstest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
public class SetHomeLocationActivity extends AppCompatActivity {
private EditText etAddress;
private EditText etLongitude;
private EditText etLatitude;
private Button btnClear;//清空当前框内全部数据
private Button btnBtnUpData;//点击自动根据地址或经纬度补全信息
private Button btnGetLocation;//获取当前地址,并显示在输入框内
private Button btnSetHome;//设置完成,返回地图界面
private Button btnBtnGoBack;//直接返回地图界面
private double mLongitude = 0;
private double mLatitude = 0;
/**
* 该标记位功能说明:默认按下设置完成返回地图按钮后发送回MainActivity活动中
* 用于确保设置成功,同时若直接返回,则说明没有进行设置,将0发送回去进行判断
*/
private int Set_flg = 1;//设置地址是否成功标记位
private int Set_false_flg = 0;//并未设置地址,保留原有地址返回地图定位界面
private com.baidu.location.LocationClient mLocClient;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.set_home_location);
etAddress = findViewById(R.id.et_address);//地址
etLongitude = findViewById(R.id.et_latitude);//经度
etLatitude = findViewById(R.id.et_longitude);//纬度
/**
* 设置传入的默认的清远地址
*/
Toast.makeText(this, "此时是默认地址,如需重新设置,可清空数据", Toast.LENGTH_LONG).show();
mLongitude = getIntent().getDoubleExtra("longitude", 0.0);
mLatitude = getIntent().getDoubleExtra("latitude", 0.0);
etLatitude.setText(String.valueOf(mLatitude));
etLongitude.setText(String.valueOf(mLongitude));
/**
* 作者:唐瑛琪
* 邮箱:[email protected]
* 以下是点击按钮事件的监控操作
* 功能:清空、补全、获取、设置并返回、直接返回
*/
btnClear = findViewById(R.id.btn_set_home_location_clear);
btnBtnUpData = findViewById(R.id.btn_set_home_location_upData);
btnGetLocation = findViewById(R.id.btn_set_home_location_confirm);
btnSetHome = findViewById(R.id.btn_set_home_ok_goBack_diTu);
btnBtnGoBack = findViewById(R.id.btn_goBack);
btnClear.setOnClickListener(new View.OnClickListener() {//点击按钮清空已输入的数据信息
@Override
public void onClick(View v) {
etAddress.setText("");
etLongitude.setText("");
etLatitude.setText("");
}
});
btnBtnUpData.setOnClickListener(new View.OnClickListener() {//通过按钮将地址或经纬度补全
@Override
public void onClick(View v) {
String address = etAddress.getText().toString().trim();
String latitude = etLatitude.getText().toString().trim();
String longitude = etLongitude.getText().toString().trim();
if (!TextUtils.isEmpty(address)) {
// 使用Geocode API查询经纬度信息
// 创建地理编码检索实例
com.baidu.mapapi.search.geocode.GeoCoder geoCoder = com.baidu.mapapi.search.geocode.GeoCoder.newInstance();
// 设置地理编码检索监听者
geoCoder.setOnGetGeoCodeResultListener(new com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener() {
@Override
public void onGetGeoCodeResult(com.baidu.mapapi.search.geocode.GeoCodeResult result) {
if (result == null || result.getLocation() == null)
Toast.makeText(SetHomeLocationActivity.this, "未能找到对应的经纬度信息", Toast.LENGTH_SHORT).show();
else {
etLatitude.setText(String.valueOf(result.getLocation().latitude));
etLongitude.setText(String.valueOf(result.getLocation().longitude));
}
}
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
// 不需要实现该方法
}
});
// 发起地理编码检索请求
geoCoder.geocode(new com.baidu.mapapi.search.geocode.GeoCodeOption().city("").address(address));
} else if (!TextUtils.isEmpty(latitude) && !TextUtils.isEmpty(longitude)) {
// 使用Reverse Geocode API查询地址信息
// 创建反地理编码检索实例
com.baidu.mapapi.search.geocode.GeoCoder geoCoder = com.baidu.mapapi.search.geocode.GeoCoder.newInstance();
// 设置反地理编码检索监听者
geoCoder.setOnGetGeoCodeResultListener(new com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener() {
@Override
public void onGetGeoCodeResult(com.baidu.mapapi.search.geocode.GeoCodeResult result) {
// 不需要实现该方法
}
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
if (result == null || result.getAddress() == null) {
Toast.makeText(SetHomeLocationActivity.this, "未能找到对应的地址信息", Toast.LENGTH_SHORT).show();
} else {
etAddress.setText(result.getAddress());
}
}
});
// 发起反地理编码检索请求
com.baidu.mapapi.model.LatLng latLng = new com.baidu.mapapi.model.LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude));
geoCoder.reverseGeoCode(new com.baidu.mapapi.search.geocode.ReverseGeoCodeOption().location(latLng));
}
}
});
btnGetLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 创建百度地图LocationClient实例
try {
mLocClient = new com.baidu.location.LocationClient(SetHomeLocationActivity.this);
} catch (Exception e) {
e.printStackTrace();
}
// 配置定位参数
com.baidu.location.LocationClientOption option = new com.baidu.location.LocationClientOption();
option.setCoorType("bd09ll");
option.setIsNeedAddress(true);
mLocClient.setLocOption(option);
// 设置定位监听器
mLocClient.registerLocationListener(new com.baidu.location.BDAbstractLocationListener() {
@Override
public void onReceiveLocation(com.baidu.location.BDLocation location) {
// 获取详细地址信息
String address = location.getAddrStr();
etAddress.setText(address);
// 获取纬度和经度
double latitude = location.getLatitude();
double longitude = location.getLongitude();
etLatitude.setText(String.valueOf(latitude));
etLongitude.setText(String.valueOf(longitude));
// 停止定位
mLocClient.stop();
}
});
// 启动定位
mLocClient.start();
}
});
btnSetHome.setOnClickListener(new View.OnClickListener() {//返回有用信息到MainActivity活动中,即返回经纬度数据
@Override
public void onClick(View v) {
if (checkInput()) {
// 设置家庭地址信息并返回地图界面
mLongitude = Double.parseDouble(etLongitude.getText().toString());
mLatitude = Double.parseDouble(etLatitude.getText().toString());
Intent intent = new Intent(SetHomeLocationActivity.this, MainActivity.class);
intent.putExtra("Longitude", mLongitude);
intent.putExtra("Latitude", mLatitude);
intent.putExtra("Set_home_flg",Set_flg);//告诉MainActivity活动已经设置成功
startActivity(intent);
} else {
Toast.makeText(SetHomeLocationActivity.this, "请至少输入家庭地址、经度和纬度中的一项、并补全信息", Toast.LENGTH_SHORT).show();
}
}
});
btnBtnGoBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SetHomeLocationActivity.this, MainActivity.class);
intent.putExtra("Set_home_flg",Set_false_flg);//告诉MainActivity活动并未设置
startActivity(intent);
}
});
}
// 检查输入数据是否为空
private boolean checkInput() {
if (TextUtils.isEmpty(etAddress.getText().toString().trim())
&& (TextUtils.isEmpty(etLongitude.getText().toString().trim())
||TextUtils.isEmpty(etLatitude.getText().toString().trim()))) {//经纬度要两个都有才能进行设置,属于一个数据
return false;
}else if((TextUtils.isEmpty(etLatitude.getText().toString().trim()) && TextUtils.isEmpty(etLongitude.getText().toString().trim()))
||TextUtils.isEmpty(etLatitude.getText().toString().trim())|| TextUtils.isEmpty(etLongitude.getText().toString().trim())){//经纬度都为空,其中一个为空
String address = etAddress.getText().toString().trim();
if (!TextUtils.isEmpty(address)) {
// 使用Geocode API查询经纬度信息
// 创建地理编码检索实例
com.baidu.mapapi.search.geocode.GeoCoder geoCoder = com.baidu.mapapi.search.geocode.GeoCoder.newInstance();
// 设置地理编码检索监听者
geoCoder.setOnGetGeoCodeResultListener(new com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener() {
@Override
public void onGetGeoCodeResult(com.baidu.mapapi.search.geocode.GeoCodeResult result) {
if (result == null || result.getLocation() == null)
Toast.makeText(SetHomeLocationActivity.this, "未能找到对应的经纬度信息", Toast.LENGTH_SHORT).show();
else {
etLatitude.setText(String.valueOf(result.getLocation().latitude));
etLongitude.setText(String.valueOf(result.getLocation().longitude));
}
}
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
// 不需要实现该方法
}
});
// 发起地理编码检索请求
geoCoder.geocode(new com.baidu.mapapi.search.geocode.GeoCodeOption().city("").address(address));
}
return false;
}
return true;
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
}
@Override
protected void onDestroy() {
super.onDestroy();
// 退出时销毁定位
mLocClient.stop();
}
}
然后是新增加活动的layout文件,具体代码如下:
okok,以上就是新增加的功能,具体功能也不介绍了,具体功能实现在代码中以经有很多注释。