百度地图定位APP

292 阅读6分钟

新建一个项目界面布局activity_main.xml代码:包含一个id为tv的TextView控件,用于显示定位结果

将权限进行配置:

<!-- 2个定位权限是危险权限并处于一个权限组,需要动态申请 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/><!--精确定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/><!--粗糙定位-->

<!-- 网络权限和WiFi权限是普通权限,不需要动态申请 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><!--网络状态-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><!--WiFi状态-->
界面程序MainActivity主程序代码
/*
    Android提供了三种定位方式(GPS定位、WiFI定位和基站定位)获得定位信息—经纬度【基站定位也称移动网络定位,也称为GPRS定位】
    打开位置服务时,必须从三种定位模式(高精度—混合定位、节电—网络定位和单独的GPS定位)中选择一种,通常选择混合定位
    GPS定位精度高,但可能由于GPS信号弱而较慢甚至获取不到
    GPS定位对应于权限android.permission.ACCESS_FINE_LOCATION
    网络定位(WiFi或移动网络)定位速度快,但精度相对GPS低
    网络定位对应于权限android.permission.ACCESS_COARSE_LOCATION【COARSE系粗糙之意】
 */
public class MainActivity extends AppCompatActivity {

    LocationManager lm;  //位置服务管理器
    ConnectivityManager cm;  //网络连接管理器
    WifiManager wfm;  //Wifi管理器
    TextView tv;  //显示经纬度
    final static int LOCATION_SETTING_REQUEST_CODE = 100;
    final static int NETWORK_SETTING_REQUEST_CODE = 200;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //如果没有ACCESS_COARSE_LOCATION权限,动态请求用户允许使用该权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
        }else {
            prepareLocatingService();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 1:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {  //危险权限
                    prepareLocatingService();
                } else {
                    Toast.makeText(this, "没有授予定位权限!", Toast.LENGTH_LONG).show();
                    finish();
                }
        }
    }

     //定位服务预备
     void prepareLocatingService() {
        tv = findViewById(R.id.tv);
        lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        //android API 24之后,必须使用 getApplicationContext()
        wfm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

        //打开定位服务时(有多种检测方法)
        if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) || lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            //打开位置服务作为定位的入口
            locatingService();  //方法调用
        } else {
            new AlertDialog.Builder(this)
                    .setIcon(R.mipmap.ic_launcher)
                    .setTitle("消息框")
                    .setMessage("请先打开定位服务!")
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            //定位服务设置意图
                            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                            //有返回值的调用,设置定位设置请求码
                            startActivityForResult(intent, LOCATION_SETTING_REQUEST_CODE);
                        }
                    })
                    .show();
            Log.i("wustwzxabc", "test1111");  //未阻塞,即用户单击“确定”按钮前此信息已经输出
            //即Android里的AlertDialog,是非阻塞的!
        }
    }

     void locatingService() {  //已开启位置服务时
        if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER) && lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            //使用混合定位(GPS+网络)
            if (cm.getActiveNetworkInfo() != null) {
                networkLocation();  //为了尽快获取定位数据,假定网络定位优先
            } else {
                GPSLocation();  //使用GPS定位
            }
        } else {
            if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {   //使用单GPS定位方式
                GPSLocation();
            } else {
                if (lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {   //未开启GPS定位—即网络定位—节电模式
                    networkLocation();
                }
            }
        }
    }

     void GPSLocation() {
        tv.setText("GPS定位中...");
        Toast.makeText(getApplicationContext(), "GPS定位", Toast.LENGTH_LONG).show();
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, new LocationListener() {
            @Override
            public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onProviderEnabled(String arg0) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onProviderDisabled(String arg0) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onLocationChanged(Location location) {
                // TODO Auto-generated method stub
                String string1 = "纬度为:" + location.getLatitude() + "\n经度为:" + location.getLongitude();
                tv.setText(string1);
            }
        });
    }

     void networkLocation() {
        if (cm.getActiveNetworkInfo() != null) { //有网络连接时
            if (wfm.isWifiEnabled()) { //WIFI有效时
                Toast.makeText(getApplicationContext(), "WiFi方式的网络定位", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(getApplicationContext(), "基站方式的网络定位", Toast.LENGTH_LONG).show();
            }
        } else { //没有网络连接时
            new AlertDialog.Builder(this)
                    .setIcon(R.mipmap.ic_launcher)
                    .setTitle("消息框")
                    .setMessage("无网络连接!请先设置一种网络连接...")
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            //进入网络连接设置
                            Intent intent = new Intent(Settings.ACTION_SETTINGS);
                            //有返回值的调用,设置网络设置请求码
                            startActivityForResult(intent, NETWORK_SETTING_REQUEST_CODE);
                        }
                    })
                    .show();
        }

        //下面的请求位置(实时)更新,Android 6.0及以上版本需要在首次运行时动态加载上述权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 1, new LocationListener() {  //实时监听
            @Override
            public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onProviderEnabled(String arg0) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onProviderDisabled(String arg0) {
                // TODO Auto-generated method stub
            }

            @Override
            public void onLocationChanged(Location location) {
                // TODO Auto-generated method stub
                String string2 = "纬度为:" + location.getLatitude() + "\n经度为:" + location.getLongitude();
                //Toast.makeText(getApplicationContext(), string2, Toast.LENGTH_LONG).show();
                tv.setText(string2);
            }
        });
    }

    @Override  //有返回值的调用
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //只用到了请求码
        if (requestCode == LOCATION_SETTING_REQUEST_CODE || requestCode == NETWORK_SETTING_REQUEST_CODE) {
            prepareLocatingService();
        }
    }
}

申请百度开发者账号,访问百度官方网站选择:开发文档->Android 地图SDK->产品下载->自定义下载,勾选百度定位包(至少选择基础定位和基础地图)后下载。

QQ图片20211204214923.png

在项目里,新建名为example10_2的模块 选择模块视图为Project,复制定位包BaiduLBS_Android.jar至模块example10 _2的libs文件夹里,然后右键jar文件,选择"Add As Library" 在main文件夹下新建名为jniLibs的文件夹,复制存放.so文件(share object)的多个文件夹至jniLibs文件夹

QQ图片20211204220221.png

在模块的清单文件里,增加如下权限:

<!--百度定位所需要权限,前面2个是LOCATE权限组的2个危险权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!--百度定位所需要的普通权限-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <!--因为程序要与百度云服务交互-->

在Android Studio里,获得SHA1的方法是单击屏幕右上方的Gradle工具后,展开项目的任何一个模块里的文件夹Tasks/android,可以看到签名报告文件SignningReport。双击signingReport,即可出现本机的SHA1。

QQ图片20211204214919.png 布局活动main.xml代码:添加一个id为tvpositionText的TextView控件 界面程序MainActivity.java代码如下

/*
    百度定位信息,使用一个TextView控件显示
    一般需要打开定位服务,选择高精度定位模式,有网络连接
    需要在清单文件里使用百度云服务(参见清单文件service标签)
    需要创建应用(模块)的Key,并写入清单文件(参见清单文件meta标签)
*/
public class MainActivity extends AppCompatActivity {

    public LocationClient mLocationClient; //定位客户端
    TextView tv_positionText;  //显示定位信息控件

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //如果没有定位权限,动态请求用户允许使用该权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
        }else {
            requestLocation();
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "没有定位权限!", Toast.LENGTH_LONG).show();
                    finish();
                } else {
                    requestLocation();
                }
        }
    }

    private void requestLocation() {
        initLocation();  //初始化
        mLocationClient.start();  //开始定位
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();  
        mLocationClient.stop();
    }

    private void initLocation() {   
        setContentView(R.layout.activity_main);
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        tv_positionText = findViewById(R.id.tv_positionText);
        //定位客户端操作
        LocationClientOption option = new LocationClientOption();
        //设置扫描时间间隔(单位:毫秒)
        option.setScanSpan(1000);
        //设置定位模式,三选一
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        /*option.setLocationMode(LocationClientOption.LocationMode.Battery_Saving);
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);*/
        //设置需要地址信息
        option.setIsNeedAddress(true);
        //保存定位参数
        mLocationClient.setLocOption(option);
    }

    class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
            StringBuffer currentPosition = new StringBuffer();
            currentPosition.append("Longitude:").append(bdLocation.getLongitude()).append("\n");
            currentPosition.append("Latitude:").append(bdLocation.getLatitude()).append("\n");
            currentPosition.append("Country:").append(bdLocation.getCountry()).append("\n");
            currentPosition.append("Province:").append(bdLocation.getProvince()).append("\n");
            currentPosition.append("City:").append(bdLocation.getCity()).append("\n");
            currentPosition.append("District:").append(bdLocation.getDistrict()).append("\n");
            currentPosition.append("Street:").append(bdLocation.getStreet()).append("\n");
            currentPosition.append("Address:").append(bdLocation.getAddrStr());
            tv_positionText.setText(currentPosition);
        }
    }
}

界面布局使用帧布局,包含有重叠效果的地图和位置文本,activity_main.xml的完整代码如下:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <!--百度地图控件-->
    <com.baidu.mapapi.map.MapView
        android:id="@+id/bmapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="true" />
    <!--位置文本布局的背景色代码的前2位代码为透明度-->
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#e0000000"
        android:orientation="vertical" >
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="12dp"
            android:layout_marginTop="20dp"
            android:orientation="horizontal" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="纬度:"
                android:textColor="#ffffff"
                android:textSize="15dp" />
            <TextView
                android:id="@+id/tv_Lat"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:textColor="#ffffff"
                android:textSize="15dp" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="12dp"
            android:layout_marginTop="10dp"
            android:orientation="horizontal" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="经度:"
                android:textColor="#ffffff"
                android:textSize="15dp" />
            <TextView
                android:id="@+id/tv_Lon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:textColor="#ffffff"
                android:textSize="15dp" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="12dp"
            android:layout_marginTop="10dp"
            android:orientation="horizontal" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="地址:"
                android:textColor="#ffffff"
                android:textSize="15dp" />

            <TextView
                android:id="@+id/tv_Add"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:textColor="#ffffff"
                android:textSize="15dp" />
        </LinearLayout>
    </LinearLayout>
</FrameLayout>

界面程序MainActivity.java代码如下:

/*
    百度地图应用,包含定位信息和地图显示
    一般需要打开定位服务,选择高精度定位模式,有网络连接
    需要在清单文件里使用百度云服务(参见清单文件service标签)
    需要创建应用(模块)的Key,并写入清单文件(参见清单文件meta标签)
*/
public class MainActivity extends AppCompatActivity {

    LocationClient mLocationClient;  //定位客户端
    MapView mapView;  //Android Widget地图控件
    BaiduMap baiduMap;
    boolean isFirstLocate = true;

    TextView tv_Lat;  //纬度
    TextView tv_Lon;  //经度
    TextView tv_Add;  //地址

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //如果没有定位权限,动态请求用户允许使用该权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
        }else {
            requestLocation();
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "没有定位权限!", Toast.LENGTH_LONG).show();
                    finish();
                } else {
                    requestLocation();
                }
        }
    }
    private void requestLocation() {
        initLocation();
        mLocationClient.start();
    }
    private void initLocation() {  //初始化
        mLocationClient = new LocationClient(getApplicationContext());
        mLocationClient.registerLocationListener(new MyLocationListener());
        SDKInitializer.initialize(getApplicationContext());
        setContentView(R.layout.activity_main);

        mapView = findViewById(R.id.bmapView);
        baiduMap = mapView.getMap();
        tv_Lat = findViewById(R.id.tv_Lat);
        tv_Lon = findViewById(R.id.tv_Lon);
        tv_Add = findViewById(R.id.tv_Add);

        LocationClientOption option = new LocationClientOption();
        //设置扫描时间间隔
        option.setScanSpan(1000);
        //设置定位模式,三选一
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        /*option.setLocationMode(LocationClientOption.LocationMode.Battery_Saving);
        option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);*/
        //设置需要地址信息
        option.setIsNeedAddress(true);
        //保存定位参数
        mLocationClient.setLocOption(option);
    }
    //内部类,百度位置监听器
    private class MyLocationListener  implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
            tv_Lat.setText(bdLocation.getLatitude()+"");
            tv_Lon.setText(bdLocation.getLongitude()+"");
            tv_Add.setText(bdLocation.getAddrStr());
            if(bdLocation.getLocType()==BDLocation.TypeGpsLocation || bdLocation.getLocType()==BDLocation.TypeNetWorkLocation){
                navigateTo(bdLocation);
            }
        }
    }
    private void navigateTo(BDLocation bdLocation) {
        if(isFirstLocate){
            LatLng ll = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
            MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
            baiduMap.animateMapStatus(update);
            isFirstLocate = false;
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
    }
    @Override
    protected void onPause() {
        super.onPause();
        mapView.onResume();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocationClient.stop();
        mapView.onDestroy();
    }
}

QQ图片20211204214905.png