Android中级篇之百度地图SDK v3.5.0-一步一步带你仿各大主流APP地图定位移动选址功能

定位+移动选址

  • 百学须先立志—学前须知:

    我们经常在各大主流APP上要求被写上地址,如百度外卖、爱鲜蜂收货地址等等;其中他们大多数是可以让我们在地图上移动选址。就如下面这段GIF演示的一样:

  • 尽信书,不如无书—能学到什么?

    1、地图状态MapStatus类及监听setOnMapStatusChangeListener

    2、定位LocationClient类

    3、反地理编码GeoCoder类

  • 工欲善其事必先利其器—申请Key

    百度地图访问应用(AK)申请地址:http://lbsyun.baidu.com/apiconsole/key

    如果你是第一次申请的话可以参看我的另一篇教程:Android中级篇之百度地图SDK v3.5.0-申请密钥详解[AndroidStudio下获取SHA1]

  • 兵马未动,粮草先行—导入百度地图jar包

    1、 进入百度地图API-首页

    2、鼠标移动到 开发 标签页上,选择 Android地图SDK

    3、选择 相关下载

    4、选择 全部下载 (此时这里会跳转到新的下载页面)

    5、选择 相对应的开发包(本教程大家选择和下图标注的一样即可)

    6、导入jar包到工程

    如果你是第一次导入的话可以参看我另一篇教程:Android中级篇之百度地图SDK v3.5.0-配置环境及发布[图解AndroidStudio下配置.so文件] 这里呢就不再赘述了。

  • 权限及服务—AndroidManifest

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.scp">
    
        <!-- SDK2.1新增获取用户位置信息 -->
        <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
        <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
        <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
        <!-- SDK1.5需要android.permission.GET_TASKS权限判断本程序是否为当前运行的应用? -->
        <uses-permission android:name="android.permission.GET_TASKS" />
        <uses-permission android:name="android.permission.WRITE_SETTINGS" />
        <!-- 这个权限用于进行网络定位-->
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
        <!-- 这个权限用于访问GPS定位-->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
        <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
        <!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
        <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
        <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
        <!-- 用于读取手机当前的状态-->
        <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
        <!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
        <!-- 访问网络,网络定位需要上网-->
        <uses-permission android:name="android.permission.INTERNET" />
        <!-- SD卡读取权限,用户写入离线定位数据-->
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"></uses-permission>
        <!--允许应用读取低级别的系统日志文件 -->
        <uses-permission android:name="android.permission.READ_LOGS"></uses-permission>
        <!-- 定位所需的权限 -->
        <uses-permission android:name="android.permission.VIBRATE" />
    
        <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    
        <!--对于很高的分辨率,除采用相应的图片外,还需要加上如下配置,来更好的适配屏幕 -->
        <supports-screens
            android:anyDensity="true"
            android:largeScreens="true"
            android:normalScreens="true"
            android:smallScreens="true" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
            <meta-data
                android:name="com.baidu.lbsapi.API_KEY"
                android:value="你申请的百度地图KEY" />
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
        <service
            android:name="com.baidu.location.f"
            android:enabled="true"
            android:process=":remote">
            <intent-filter>
                <action android:name="com.baidu.location.service_v2.2"></action>
            </intent-filter>
        </service>
    
    </manifest>
    

  • 配置.so文件及其他—build.gradle

    apply plugin: ‘com.android.application‘
    
    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.0"
    
        defaultConfig {
            applicationId "com.scp"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                //代码混淆
                minifyEnabled false
                //zip优化
                zipAlignEnabled true
                //移除无用的resource文件
                shrinkResources true
                proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.txt‘
            }
        }
        sourceSets {
            main {
                jniLibs.srcDirs = [‘libs‘]
            }
        }
    }
    
    dependencies {
        compile fileTree(include: [‘*.jar‘], dir: ‘libs‘)
        compile ‘com.android.support:appcompat-v7:23.0.0‘
        compile files(‘libs/BaiduLBS_Android.jar‘)
    }
    

  • 主布局—activity_main.xml

    首先我们先分析一下,整个布局结构上面是百度的 MapView (地图区域)下面是一个 ListView(选址列表区域) ,乍一看好像是如下图描述一样:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <com.baidu.mapapi.map.MapView
            android:id="@+id/main_bdmap"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:onClick="true"></com.baidu.mapapi.map.MapView>
    
        <ListView
            android:id="@+id/main_pois"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"></ListView>
    
    </LinearLayout>

    从布局中我们可以看到 MapView 占了250dp(大家自己可以随意给个值,不要太小即可)。下面的 ListView 则是填充了剩余的空间。

  • 第一步:基础地图

    public class MainActivity extends AppCompatActivity {
    
        private MapView mMapView;
        private BaiduMap mBaiduMap;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //在使用SDK各组件之前初始化context信息,传入ApplicationContext
            //注意该方法要再setContentView方法之前实现
            SDKInitializer.initialize(getApplicationContext());
            //requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
            initView();
        }
    
        private void initView() {
            mMapView = (MapView) findViewById(R.id.main_bdmap);
            mBaiduMap = mMapView.getMap();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            // activity 恢复时同时恢复地图控件
            mMapView.onResume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            // activity 暂停时同时暂停地图控件
            mMapView.onPause();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
    
            // activity 销毁时同时销毁地图控件
            mMapView.onDestroy();
            mMapView = null;
        }
    
    }

    这里我们的 MainActivity 继承的是 AppCompatActivity,继承 Activity 也行。

    //在使用SDK各组件之前初始化context信息,传入ApplicationContext
    //注意该方法要再setContentView方法之前实现
    SDKInitializer.initialize(getApplicationContext());

    这段代码一段要放在 setContentView(R.layout.activity_main); 之前。继续往下看,其中有一句代码requestWindowFeature(Window.FEATURE_NO_TITLE);被注释掉了,需要去掉标题栏的朋友可以加上这句代码。下面呢还有另外一种方法去掉标题栏,打开我们的 style.xml

    改成 Theme.AppCompat.Light.NoActionBar

    运行效果图:

  • 第二步:定位

    继续书写我们的MainActivity里面的代码:

    public class MainActivity extends AppCompatActivity implements BDLocationListener, OnGetGeoCoderResultListener, BaiduMap.OnMapStatusChangeListener {
    
        private MapView mMapView;
        private BaiduMap mBaiduMap;
        private ListView poisLL;
        /**
         * 定位模式
         */
        private MyLocationConfiguration.LocationMode mCurrentMode;
        /**
         * 定位端
         */
        private LocationClient mLocClient;
        /**
         * 是否是第一次定位
         */
        private boolean isFirstLoc = true;
        /**
         * 定位坐标
         */
        private LatLng locationLatLng;
        /**
         * 定位城市
         */
        private String city;
        /**
         * 反地理编码
         */
        private GeoCoder geoCoder;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //在使用SDK各组件之前初始化context信息,传入ApplicationContext
            //注意该方法要再setContentView方法之前实现
            SDKInitializer.initialize(getApplicationContext());
            //requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
            initView();
        }
    
        private void initView() {
            mMapView = (MapView) findViewById(R.id.main_bdmap);
            mBaiduMap = mMapView.getMap();
    
            poisLL = (ListView) findViewById(R.id.main_pois);
    
            //定义地图状态
            MapStatus mMapStatus = new MapStatus.Builder().zoom(18).build();
            MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
            //改变地图状态
            mBaiduMap.setMapStatus(mMapStatusUpdate);
    
            //地图状态改变相关监听
            mBaiduMap.setOnMapStatusChangeListener(this);
    
            //开启定位图层
            mBaiduMap.setMyLocationEnabled(true);
    
            //定位图层显示方式
            mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL;
    
            /**
             * 设置定位图层配置信息,只有先允许定位图层后设置定位图层配置信息才会生效
             * customMarker用户自定义定位图标
             * enableDirection是否允许显示方向信息
             * locationMode定位图层显示方式
             */
            mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(mCurrentMode, true, null));
    
            //初始化定位
            mLocClient = new LocationClient(this);
            //注册定位监听
            mLocClient.registerLocationListener(this);
    
            //定位选项
            LocationClientOption option = new LocationClientOption();
            /**
             * coorType - 取值有3个:
             * 返回国测局经纬度坐标系:gcj02
             * 返回百度墨卡托坐标系 :bd09
             * 返回百度经纬度坐标系 :bd09ll
             */
            option.setCoorType("bd09ll");
            //设置是否需要地址信息,默认为无地址
            option.setIsNeedAddress(true);
            //设置是否需要返回位置语义化信息,可以在BDLocation.getLocationDescribe()中得到数据,ex:"在天安门附近", 可以用作地址信息的补充
            option.setIsNeedLocationDescribe(true);
            //设置是否需要返回位置POI信息,可以在BDLocation.getPoiList()中得到数据
            option.setIsNeedLocationPoiList(true);
            /**
             * 设置定位模式
             * Battery_Saving
             * 低功耗模式
             * Device_Sensors
             * 仅设备(Gps)模式
             * Hight_Accuracy
             * 高精度模式
             */
            option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
            //设置是否打开gps进行定位
            option.setOpenGps(true);
            //设置扫描间隔,单位是毫秒 当<1000(1s)时,定时定位无效
            option.setScanSpan(1000);
    
            //设置 LocationClientOption
            mLocClient.setLocOption(option);
    
            //开始定位
            mLocClient.start();
    
        }
    
        /**
         * 定位监听
         *
         * @param bdLocation
         */
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
    
            //如果bdLocation为空或mapView销毁后不再处理新数据接收的位置
            if (bdLocation == null || mBaiduMap == null) {
                return;
            }
    
            //定位数据
            MyLocationData data = new MyLocationData.Builder()
                    //定位精度bdLocation.getRadius()
                    .accuracy(bdLocation.getRadius())
                            //此处设置开发者获取到的方向信息,顺时针0-360
                    .direction(bdLocation.getDirection())
                            //经度
                    .latitude(bdLocation.getLatitude())
                            //纬度
                    .longitude(bdLocation.getLongitude())
                            //构建
                    .build();
    
            //设置定位数据
            mBaiduMap.setMyLocationData(data);
    
            //是否是第一次定位
            if (isFirstLoc) {
                isFirstLoc = false;
                LatLng ll = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
                MapStatusUpdate msu = MapStatusUpdateFactory.newLatLngZoom(ll, 18);
                mBaiduMap.animateMapStatus(msu);
            }
    
            //获取坐标,待会用于POI信息点与定位的距离
            locationLatLng = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
            //获取城市,待会用于POISearch
            city = bdLocation.getCity();
    
            //创建GeoCoder实例对象
            geoCoder = GeoCoder.newInstance();
            //发起反地理编码请求(经纬度->地址信息)
            ReverseGeoCodeOption reverseGeoCodeOption = new ReverseGeoCodeOption();
            //设置反地理编码位置坐标
            reverseGeoCodeOption.location(new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude()));
            geoCoder.reverseGeoCode(reverseGeoCodeOption);
    
            //设置查询结果监听者
            geoCoder.setOnGetGeoCodeResultListener(this);
        }
    
        //地理编码查询结果回调函数
        @Override
        public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
        }
    
        //反地理编码查询结果回调函数
        @Override
        public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
            List<PoiInfo> poiInfos = reverseGeoCodeResult.getPoiList();
            PoiAdapter poiAdapter = new PoiAdapter(MainActivity.this, poiInfos);
            poisLL.setAdapter(poiAdapter);
        }
    
        /**
         * 手势操作地图,设置地图状态等操作导致地图状态开始改变
         *
         * @param mapStatus 地图状态改变开始时的地图状态
         */
        @Override
        public void onMapStatusChangeStart(MapStatus mapStatus) {
        }
    
        /**
         * 地图状态变化中
         *
         * @param mapStatus 当前地图状态
         */
        @Override
        public void onMapStatusChange(MapStatus mapStatus) {
        }
    
        /**
         * 地图状态改变结束
         *
         * @param mapStatus 地图状态改变结束后的地图状态
         */
        @Override
        public void onMapStatusChangeFinish(MapStatus mapStatus) {
            //地图操作的中心点
            LatLng cenpt = mapStatus.target;
            geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(cenpt));
        }
    
        //回退键
        @Override
        public void onBackPressed() {
            finish();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            // activity 恢复时同时恢复地图控件
            mMapView.onResume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            // activity 暂停时同时暂停地图控件
            mMapView.onPause();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
    
            //退出时停止定位
            mLocClient.stop();
            //退出时关闭定位图层
            mBaiduMap.setMyLocationEnabled(false);
    
            // activity 销毁时同时销毁地图控件
            mMapView.onDestroy();
    
            //释放资源
            if (geoCoder != null) {
                geoCoder.destroy();
            }
    
            mMapView = null;
        }
    }
    

    代码分段分析:

    这里我们放大了地图,zoom(18)【地图缩放级别 3~20】,接下来对我们的定位选项做一个简单的说明:

    当我们定位完了之后,我们就可以对定位好的数据进行处理了,简单说明一下我们的定位监听做了哪些事情:

    定位好了之后我们进行过反地理编码,下面说明一下反地理编码监听里面做了哪些事情:

  • PoiAdapter

    这里会用到一张图 baidumap_ico_poi_on.png 大家右键另存为就行了:

    适配器视图 locationpois.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingLeft="5dp">
    
        <LinearLayout
            android:id="@+id/locationpois_linearlayout"
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/locationpois_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    
        <TextView
            android:id="@+id/locationpois_address"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </LinearLayout>

    布局简单说明:

    实现类 PoiAdapter

    public class PoiAdapter extends BaseAdapter {
        private Context context;
        private List<PoiInfo> pois;
        private LinearLayout linearLayout;
    
        PoiAdapter(Context context, List<PoiInfo> pois) {
            this.context = context;
            this.pois = pois;
        }
    
        @Override
        public int getCount() {
            return pois.size();
        }
    
        @Override
        public Object getItem(int position) {
            return pois.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null) {
                convertView = LayoutInflater.from(context).inflate(R.layout.locationpois_item, null);
                linearLayout = (LinearLayout) convertView.findViewById(R.id.locationpois_linearlayout);
                holder = new ViewHolder(convertView);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            if (position == 0 && linearLayout.getChildCount() < 2) {
                ImageView imageView = new ImageView(context);
                ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(32, 32);
                imageView.setLayoutParams(params);
                imageView.setBackgroundColor(Color.TRANSPARENT);
                imageView.setImageResource(R.mipmap.baidumap_ico_poi_on);
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                linearLayout.addView(imageView, 0, params);
                holder.locationpoi_name.setTextColor(Color.parseColor("#FF5722"));
            }
            PoiInfo poiInfo = pois.get(position);
            holder.locationpoi_name.setText(poiInfo.name);
            holder.locationpoi_address.setText(poiInfo.address);
            return convertView;
        }
    
        class ViewHolder {
            TextView locationpoi_name;
            TextView locationpoi_address;
    
            ViewHolder(View view) {
                locationpoi_name = (TextView) view.findViewById(R.id.locationpois_name);
                locationpoi_address = (TextView) view.findViewById(R.id.locationpois_address);
            }
        }
    }

    代码分段分析:

  • 地图状态变化—OnMapStatusChangeListener

    来看看我们现在运行是什么样子的:

    大家移动一下地图试试。

  • 第三步:添加定位图标

    更改 activity_main.xml 布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <RelativeLayout
                android:id="@+id/main_top_RL"
                android:layout_width="match_parent"
                android:layout_height="250dp">
    
                <com.baidu.mapapi.map.MapView
                    android:id="@+id/main_bdmap"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:onClick="true"></com.baidu.mapapi.map.MapView>
    
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:background="@android:color/transparent"
                    android:src="@mipmap/baidumap_ico_poi_on" />
            </RelativeLayout>
    
            <ListView
                android:id="@+id/main_pois"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"></ListView>
        </LinearLayout>
    
    </LinearLayout>

    此次没有任何实现代码添加或者改动,运行看一下效果:

    大家移动一下地图试试。

  • 输入关键字显示相关地址列表

    首先我们先更改 activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <RelativeLayout
                android:id="@+id/main_top_RL"
                android:layout_width="match_parent"
                android:layout_height="250dp">
    
                <com.baidu.mapapi.map.MapView
                    android:id="@+id/main_bdmap"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:onClick="true"></com.baidu.mapapi.map.MapView>
    
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:background="@android:color/transparent"
                    android:src="@mipmap/baidumap_ico_poi_on" />
            </RelativeLayout>
    
            <ListView
                android:id="@+id/main_pois"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"></ListView>
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="#ffcccccc"
                android:gravity="center"
                android:orientation="horizontal">
    
                <EditText
                    android:id="@+id/main_search_address"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@android:color/transparent"
                    android:hint="请输入地址" />
    
            </LinearLayout>
    
            <ListView
                android:id="@+id/main_search_pois"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:background="#ffcccccc"
                android:visibility="gone"></ListView>
        </LinearLayout>
    
    </RelativeLayout>

    代码说明:

    接下来书写适配器的item布局 poisearch_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/poisearch_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/poisearch_address"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
    
            <TextView
                android:id="@+id/poisearch_distance"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    
    </LinearLayout>

    代码说明:

    最终更改我们的 MainActivity 里面的代码 (请结合下面代码说明来看)

    public class MainActivity extends AppCompatActivity implements BDLocationListener, OnGetGeoCoderResultListener, 
    
    BaiduMap.OnMapStatusChangeListener, TextWatcher {
    
        private MapView mMapView;
        private BaiduMap mBaiduMap;
        private ListView poisLL;
        /**
         * 定位模式
         */
        private MyLocationConfiguration.LocationMode mCurrentMode;
        /**
         * 定位端
         */
        private LocationClient mLocClient;
        /**
         * 是否是第一次定位
         */
        private boolean isFirstLoc = true;
        /**
         * 定位坐标
         */
        private LatLng locationLatLng;
        /**
         * 定位城市
         */
        private String city;
        /**
         * 反地理编码
         */
        private GeoCoder geoCoder;
        /**
         * 界面上方布局
         */
        private RelativeLayout topRL;
        /**
         * 搜索地址输入框
         */
        private EditText searchAddress;
        /**
         * 搜索输入框对应的ListView
         */
        private ListView searchPois;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //在使用SDK各组件之前初始化context信息,传入ApplicationContext
            //注意该方法要再setContentView方法之前实现
            SDKInitializer.initialize(getApplicationContext());
            //requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
            initView();
        }
    
        private void initView() {
            mMapView = (MapView) findViewById(R.id.main_bdmap);
            mBaiduMap = mMapView.getMap();
    
            poisLL = (ListView) findViewById(R.id.main_pois);
    
            topRL = (RelativeLayout) findViewById(R.id.main_top_RL);
    
            searchAddress = (EditText) findViewById(R.id.main_search_address);
    
            searchPois = (ListView) findViewById(R.id.main_search_pois);
    
            //定义地图状态
            MapStatus mMapStatus = new MapStatus.Builder().zoom(18).build();
            MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
            //改变地图状态
            mBaiduMap.setMapStatus(mMapStatusUpdate);
    
            //地图状态改变相关监听
            mBaiduMap.setOnMapStatusChangeListener(this);
    
            //开启定位图层
            mBaiduMap.setMyLocationEnabled(true);
    
            //定位图层显示方式
            mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL;
    
            /**
             * 设置定位图层配置信息,只有先允许定位图层后设置定位图层配置信息才会生效
             * customMarker用户自定义定位图标
             * enableDirection是否允许显示方向信息
             * locationMode定位图层显示方式
             */
            mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(mCurrentMode, true, null));
    
            //初始化定位
            mLocClient = new LocationClient(this);
            //注册定位监听
            mLocClient.registerLocationListener(this);
    
            //定位选项
            LocationClientOption option = new LocationClientOption();
            /**
             * coorType - 取值有3个:
             * 返回国测局经纬度坐标系:gcj02
             * 返回百度墨卡托坐标系 :bd09
             * 返回百度经纬度坐标系 :bd09ll
             */
            option.setCoorType("bd09ll");
            //设置是否需要地址信息,默认为无地址
            option.setIsNeedAddress(true);
            //设置是否需要返回位置语义化信息,可以在BDLocation.getLocationDescribe()中得到数据,ex:"在天安门附近", 可以用作地址信息的补充
            option.setIsNeedLocationDescribe(true);
            //设置是否需要返回位置POI信息,可以在BDLocation.getPoiList()中得到数据
            option.setIsNeedLocationPoiList(true);
            /**
             * 设置定位模式
             * Battery_Saving
             * 低功耗模式
             * Device_Sensors
             * 仅设备(Gps)模式
             * Hight_Accuracy
             * 高精度模式
             */
            option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
            //设置是否打开gps进行定位
            option.setOpenGps(true);
            //设置扫描间隔,单位是毫秒 当<1000(1s)时,定时定位无效
            option.setScanSpan(1000);
    
            //设置 LocationClientOption
            mLocClient.setLocOption(option);
    
            //开始定位
            mLocClient.start();
    
        }
    
        /**
         * 定位监听
         *
         * @param bdLocation
         */
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
    
            //如果bdLocation为空或mapView销毁后不再处理新数据接收的位置
            if (bdLocation == null || mBaiduMap == null) {
                return;
            }
    
            //定位数据
            MyLocationData data = new MyLocationData.Builder()
                    //定位精度bdLocation.getRadius()
                    .accuracy(bdLocation.getRadius())
                            //此处设置开发者获取到的方向信息,顺时针0-360
                    .direction(bdLocation.getDirection())
                            //经度
                    .latitude(bdLocation.getLatitude())
                            //纬度
                    .longitude(bdLocation.getLongitude())
                            //构建
                    .build();
    
            //设置定位数据
            mBaiduMap.setMyLocationData(data);
    
            //是否是第一次定位
            if (isFirstLoc) {
                isFirstLoc = false;
                LatLng ll = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
                MapStatusUpdate msu = MapStatusUpdateFactory.newLatLngZoom(ll, 18);
                mBaiduMap.animateMapStatus(msu);
            }
    
            //获取坐标,待会用于POI信息点与定位的距离
            locationLatLng = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
            //获取城市,待会用于POISearch
            city = bdLocation.getCity();
    
            //文本输入框改变监听,必须在定位完成之后
            searchAddress.addTextChangedListener(this);
    
            //创建GeoCoder实例对象
            geoCoder = GeoCoder.newInstance();
            //发起反地理编码请求(经纬度->地址信息)
            ReverseGeoCodeOption reverseGeoCodeOption = new ReverseGeoCodeOption();
            //设置反地理编码位置坐标
            reverseGeoCodeOption.location(new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude()));
            geoCoder.reverseGeoCode(reverseGeoCodeOption);
    
            //设置查询结果监听者
            geoCoder.setOnGetGeoCodeResultListener(this);
        }
    
        //地理编码查询结果回调函数
        @Override
        public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
        }
    
        //反地理编码查询结果回调函数
        @Override
        public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
            List<PoiInfo> poiInfos = reverseGeoCodeResult.getPoiList();
            PoiAdapter poiAdapter = new PoiAdapter(MainActivity.this, poiInfos);
            poisLL.setAdapter(poiAdapter);
        }
    
        /**
         * 手势操作地图,设置地图状态等操作导致地图状态开始改变
         *
         * @param mapStatus 地图状态改变开始时的地图状态
         */
        @Override
        public void onMapStatusChangeStart(MapStatus mapStatus) {
        }
    
        /**
         * 地图状态变化中
         *
         * @param mapStatus 当前地图状态
         */
        @Override
        public void onMapStatusChange(MapStatus mapStatus) {
        }
    
        /**
         * 地图状态改变结束
         *
         * @param mapStatus 地图状态改变结束后的地图状态
         */
        @Override
        public void onMapStatusChangeFinish(MapStatus mapStatus) {
            //地图操作的中心点
            LatLng cenpt = mapStatus.target;
            geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(cenpt));
        }
    
        /**
         * 输入框监听---输入之前
         *
         * @param s     字符序列
         * @param start 开始
         * @param count 总计
         * @param after 之后
         */
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }
    
        /**
         * 输入框监听---正在输入
         *
         * @param s      字符序列
         * @param start  开始
         * @param before 之前
         * @param count  总计
         */
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
    
        /**
         * 输入框监听---输入完毕
         *
         * @param s
         */
        @Override
        public void afterTextChanged(Editable s) {
            if (s.length() == 0 || "".equals(s.toString())) {
                searchPois.setVisibility(View.GONE);
            } else {
                //创建PoiSearch实例
                PoiSearch poiSearch = PoiSearch.newInstance();
                //城市内检索
                PoiCitySearchOption poiCitySearchOption = new PoiCitySearchOption();
                //关键字
                poiCitySearchOption.keyword(s.toString());
                //城市
                poiCitySearchOption.city(city);
                //设置每页容量,默认为每页10条
                poiCitySearchOption.pageCapacity(10);
                //分页编号
                poiCitySearchOption.pageNum(1);
                poiSearch.searchInCity(poiCitySearchOption);
                //设置poi检索监听者
                poiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {
                    //poi 查询结果回调
                    @Override
                    public void onGetPoiResult(PoiResult poiResult) {
                        List<PoiInfo> poiInfos = poiResult.getAllPoi();
                        PoiSearchAdapter poiSearchAdapter = new PoiSearchAdapter(MainActivity.this, poiInfos, locationLatLng);
                        searchPois.setVisibility(View.VISIBLE);
                        searchPois.setAdapter(poiSearchAdapter);
                    }
    
                    //poi 详情查询结果回调
                    @Override
                    public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {
                    }
                });
            }
        }
    
        //回退键
        @Override
        public void onBackPressed() {
            finish();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            // activity 恢复时同时恢复地图控件
            mMapView.onResume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            // activity 暂停时同时暂停地图控件
            mMapView.onPause();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
    
            //退出时停止定位
            mLocClient.stop();
            //退出时关闭定位图层
            mBaiduMap.setMyLocationEnabled(false);
    
            // activity 销毁时同时销毁地图控件
            mMapView.onDestroy();
    
            //释放资源
            if (geoCoder != null) {
                geoCoder.destroy();
            }
    
            mMapView = null;
        }
    
    }

    代码说明:

    最终运行效果与文章开篇展示效果一样,这里呢就不再重复贴图了。

  • GitHub

    最终项目GitHub地址:https://github.com/scp504677840/MoveMapLocation.git

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-29 12:25:22

Android中级篇之百度地图SDK v3.5.0-一步一步带你仿各大主流APP地图定位移动选址功能的相关文章

Android中级篇之百度地图SDK v3.5.0-FragmentMap地图框架[图解SupportMapFragment类]

创建一个基于Fragment的地图框架 SupportMapFragment SupportMapFragment 类,管理地图生命周期. 构造器概要 构造器和说明: SupportMapFragment() 构造函数 方法概要 限定符和类型 方法 说明 BaiduMap getBaiduMap() 获取百度地图控制器,当执行完 onCreateView 函数之后调用,否则返回 null. MapView getMapView() 获取百度地图控件 static SupportMapFragme

Android 百度地图 SDK v3.3.0 (二)--- 地图定位和图层展示

转载请注明出处:http://blog.csdn.net/tanzuai/article/details/43763159 在上一篇博客中,我们成功把地图导入了我们的项目.本篇我们准备为地图添加:第一,定位功能:第二,图层展示,第三,结合方向传感器,通过旋转手机进行道路的方向确认.有了这三个功能,地图已经可以为我服务了! 为了方便,我把所有的按钮都放到了menu菜单中. 1.在AndroidManifest.xml配一个service <!-- 定位service --> <servic

百度地图开发 SDK v3.2.0 遇到 Error inflating class com.baidu.mapapi.map.MapView解决方案

使用百度地图 SDK v3.2.0 地图时遇到的一个"找不到 com.baidu.mapapi.map.MapView"的问题 (按照API写的) 上网找了很多解决方案,不能解决,有的说需要在application里加android:name=""...,有的说需要在要在setContentView前初始化BMapManager对象 ......(现在的新版本根本找不到BMapManager这个类) 本人试了,全部无效 报错android.view.InflateE

Android 百度地图 SDK v3.0.0 (二) 定位与结合方向传感器

在上一篇博客中,我们成功把地图导入了我们的项目.本篇我们准备为地图添加:第一,定位功能:第二,与方向传感器结合,通过旋转手机进行道路的方向确认.有了这两个功能,地图已经可以为我服务了~~~~ 效果图: 好了,可以代码,为了方便,我把所有的按钮都放到了menu菜单中. 1.初次启动定位 [java] view plaincopy /** * 定位的客户端 */ private LocationClient mLocationClient; /** * 定位的监听器 */ public MyLoca

Android 百度地图 SDK v3.0.0 (四) 离线地图功能介绍

转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/37758097 一直认为地图应用支持离线地图非常重要啊.我等移动2G屌丝,流量不易.且用且珍惜. 对于官方开发指南对于离线地图的教程,提供了两种方案: 第一.手动导入,先将从官网下载的离线包解压,把vmp目录拷入SD卡根目录下的BaiduMapSDK目录内. 好吧,我表示不能接受,无视了. 第二,接口下载方法例如以下:mOffline.start(cityid);还比較靠谱,就是

Android 百度地图 SDK v3.0.0 (四) 引入离线地图功能

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37758097 一直觉得地图应用支持离线地图很重要啊,我等移动2G屌丝,流量不易,且用且珍惜. 对于官方开发指南对于离线地图的教程,提供了两种方案: 第一,手动导入,先将从官网下载的离线包解压,把vmp文件夹拷入SD卡根目录下的BaiduMapSDK文件夹内.好吧,我表示不能接受,无视了. 第二,接口下载方法如下:mOffline.start(cityid);还比较靠谱,就是没详

百度地图SDK V3.2 和百度定位SDK V4.2 完成定位功能

百度地图SDK V3.2 和百度定位SDK V4.2 完成定位功能 1.要完成定位功能,不光是要下载百度地图SDK(baidumapapi_v3_2_0.jar ; libBaiduMapSDK_v3_2_0_15.so),还需要下载百度的定位SDK(locSDK_4.2.jar; liblocSDK4d.so),需要到官网下载如上述的库和jar包.并且需要将jar包右键添加到build path中 2.需要在manifest.xml文件中添加需要的key,service以及权限.如果没有添加s

Android 百度地图 SDK v3.0.0 (一)

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37729091 最近公司要把百度地图集成的项目中,于是我就研究了一天百度地图的SDK,当前的版本:Android SDK v3.0.0 . 虽然百度地图网上相关代码比较多,大多可能都是比较旧的版本,且百度地图API的改动感觉也比较大,所以再此跟大家分享一下一天的劳动成功. 下面简单展示下,博客中会介绍的功能: 1.功能介绍 a.首先肯定是导入地图,然后就是地图模式的一些切换,普通

Android 百度地图 SDK v3.0.0 (三) 添加覆盖物Marker与InfoWindow的使用

所需的权限: ? <!-- 这个权限用于进行网络定位 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" > </uses-permission> <!-- 这个权限用于访问GPS定位 --> <uses-permission android:name="android.permission.ACCESS_FINE_LO