zoukankan      html  css  js  c++  java
  • Android开发百度地图应用——实现定位功能

    本随笔是为了记录课程中的一个安卓开发作业:做一个安卓端的地图应用,要求可以实现地图定位功能,输入一个地址后,可以在地图上定位到这个地址并给出经纬度(使用 Android Studio 开发)

    项目已托管地址:https://github.com/yunkailiu/Mybaidumap

    1.在百度地图开放平台新建项目:

      应用名称自己确定,类型选择Android SDK,启用的服务都按照默认的勾选即可,最重要的是两个SHA1的确定,按照官方文档的说明只填写开发版的即可,但创建的时候发布版是必填项(官方文档应该更新了。。。。),因此这里两个版本全部填写为开发版本的SHA1,若后续发布则再回来修改发布版的即可(具体操作可以参考官方文档)。

     

      按照官方说明获取SHA1,这里使用开发版,进入.android目录下输入指令:

      获取包名:

      按照以上步骤填写完之后会按照生成该项目的密钥,后续开发会使用:

    2.对Android Studio进行相关配置:

      首先在百度地图开发平台下载会用到的百度开发包:

       下载解压之后,将里面的 BaiduLBS_Android.jar包导入项目的libs文件夹下,右键-选择Add As Library,导入到工程中,在src/main/目录下新建jniLibs目录,将剩下的几个文件夹导入到该目录。

    3.项目开发:

      做好前面的配置工作之后就可以开始写我们的代码了,在安卓开发中要在不同的项目文件中做各自的工作,具体可参考官方给出的Hello BaiduMap实例。

      (1)在AndroidManifest.xml中添加本项目需要用到的权限、申请的密钥:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.mymap">
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
        //获取设备网络状态,禁用后无法获取网络状态
        <uses-permission android:name="android.permission.INTERNET"/>
        //网络权限,当禁用后,无法进行检索等相关业务
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        //读取设备硬件信息,统计数据
        <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
        //读取系统信息,包含系统版本等信息,用作统计
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
        //获取设备的网络状态,鉴权所需网络代理
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        //允许sd卡写权限,需写入地图数据,禁用后无法显示地图
        <uses-permission android:name="android.permission.WRITE_SETTINGS" />
        //获取统计数据
        <uses-permission android:name="android.permission.CAMERA" />
        //使用步行AR导航,配置Camera权限
        <!-- 访问精确位置的权限 -->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <!-- 这个权限用于进行网络定位-->
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    
    
        <application
            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">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <!-- 声明service组件 -->
            <service
                android:name="com.baidu.location.f"
                android:enabled="true"
                android:process=":remote" >
            </service>
            <meta-data
                android:name="com.baidu.lbsapi.API_KEY"
                android:value="刚才申请好的密钥" />
        </application>
    
    </manifest>

      (2)在activity_main.xml主界面布局文件中设置布局,因为我是通过新增菜单栏实现两个功能,因此在完成该布局前先在res中新建menu文件夹,新建menu_main.xml文件来插入菜单功能控件:

    <?xml version="1.0" encoding="utf-8"?>
    <menu 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"
          tools:context="com.example.mymap.MainActivity">
    
        <item
            android:id="@+id/menu_item_mylocation"
            android:title="我的位置"
            app:showAsAction="never" />
        <item
            android:id="@+id/menu_item_sitesearch"
            android:title="地址搜索"
            app:showAsAction="never" />
    </menu>

      (3)在activity_main.xml中写入控件代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:orientation="horizontal"
            android:id="@+id/linearLayout2"
            android:visibility="gone"
            >
            <EditText
                android:layout_width="240dp"
                android:layout_height="match_parent"
                android:hint="地址"
                android:id="@+id/editText_site" />
            <Button
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:hint="前往"
                android:id="@+id/button_sitesearch"/>
        </LinearLayout>
    
        <com.baidu.mapapi.map.MapView
            android:id="@+id/bmapView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:clickable="true" />
    </LinearLayout>

      (4)MainActivity主文件内容:

    package com.example.mymap;
    
    import android.content.Context;
    import android.os.Looper;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.Window;
    import android.view.inputmethod.InputMethodManager;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.baidu.location.BDLocation;
    import com.baidu.location.BDLocationListener;
    import com.baidu.location.LocationClient;
    import com.baidu.location.LocationClientOption;
    import com.baidu.mapapi.SDKInitializer;
    import com.baidu.mapapi.map.BaiduMap;
    import com.baidu.mapapi.map.BitmapDescriptor;
    import com.baidu.mapapi.map.BitmapDescriptorFactory;
    import com.baidu.mapapi.map.MapStatusUpdate;
    import com.baidu.mapapi.map.MapStatusUpdateFactory;
    import com.baidu.mapapi.map.MapView;
    import com.baidu.mapapi.map.MyLocationConfiguration;
    import com.baidu.mapapi.map.MyLocationData;
    import com.baidu.mapapi.model.LatLng;
    
    public class MainActivity extends AppCompatActivity {
        private MapView mMapView = null;//地图控件
        private BaiduMap mBaiduMap;//百度地图对象
        private Context context;
        //实现定位相关数据类型
        private LocationClient mLocationClient;//定位服务客户对象
        private MyLocationListener myLocationListener;//重写的监听类
        private boolean isFirstIn = true;
        private double mLatitude;//存储自己的纬度
        private double mLongitude;//存储自己的经度
        private float myCurrentX;
    
        private BitmapDescriptor myIconLocation1;//当前位置的箭头图标
        private MyOrientationListener myOrientationListener;//方向感应器类对象
        private MyLocationConfiguration.LocationMode locationMode;//定位图层显示方式
        private LinearLayout myLinearLayout2; //地址搜索区域
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            SDKInitializer.initialize(getApplicationContext());
            //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
            //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
            setContentView(R.layout.activity_main);
            this.context = this;
            initView();
            //初始化定位
            initLocation();
        }
    
        private void initLocation() {
            locationMode = MyLocationConfiguration.LocationMode.NORMAL;
            //客户端的定位服务
            mLocationClient = new LocationClient(this);
            myLocationListener = new MyLocationListener();
            //注册监听器
            mLocationClient.registerLocationListener(myLocationListener);
            //设置定位参数
            LocationClientOption option = new LocationClientOption();
            //设置坐标类型
            option.setCoorType("bd09ll");
            //设置是否需要地址信息,默认为无地址
            option.setIsNeedAddress(true);
            //设置是否打开gps进行定位
            option.setOpenGps(true);
            //设置扫描间隔为1秒
            option.setScanSpan(1000);
            //传入设置好的信息
            mLocationClient.setLocOption(option);
    
            //初始化图标,BitmapDescriptorFactory是bitmap描述信息工厂类
            myIconLocation1 = BitmapDescriptorFactory.fromResource(R.drawable.location_marker);
            //配置定义的图层,使之生效
            MyLocationConfiguration configuration = new MyLocationConfiguration(locationMode,true,myIconLocation1);
            mBaiduMap.setMyLocationConfiguration(configuration);
    
            myOrientationListener = new MyOrientationListener(context);
            //接口回调来实现实时方向的改变
            myOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() {
                @Override
                public void onOrientationChanged(float x) {
                    myCurrentX = x;
                }
            });
        }
    
        private void initView() {
            //获取地图控件引用
            mMapView = (MapView) findViewById(R.id.bmapView);
            //设置地图放大比例
            mBaiduMap = mMapView.getMap();
            MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(15.0f);
            mBaiduMap.setMapStatus(msu);
        }
    
        /**
         * 创建菜单操作
         */
        @Override
        public boolean onCreateOptionsMenu(Menu menu){
            getMenuInflater().inflate(R.menu.menu_main,menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item){
            switch (item.getItemId())
            {
                /**
                 * 返回自己所在位置
                 */
                case R.id.menu_item_mylocation:
                    getLocationByLL(mLatitude,mLongitude);
                break;
                /**
                 * 根据地址名前往所在的位置
                 */
                case R.id.menu_item_sitesearch:
                    myLinearLayout2 = (LinearLayout)findViewById(R.id.linearLayout2);
                    //显示地址搜索区域
                    myLinearLayout2.setVisibility(View.VISIBLE);
                    final EditText myEditText_site = (EditText) findViewById(R.id.editText_site);
                    Button button_site = (Button) findViewById(R.id.button_sitesearch);
    
                    button_site.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            final String site_str = myEditText_site.getText().toString();
                            new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    AddressToLatitudeLongitude at = new AddressToLatitudeLongitude(site_str);
                                    at.getLatAndLngByAddress();
                                    Looper.prepare();
                                    getLocationByLL(at.getLatitude(),at.getLongitude());
                                    Looper.loop();
                                }
                            }).start();
                            //隐藏前面地址输入区域
                            myLinearLayout2.setVisibility(View.GONE);
                            //隐藏输入法键盘
                            InputMethodManager imm = (InputMethodManager)getSystemService(
                                    Context.INPUT_METHOD_SERVICE);
                            imm.hideSoftInputFromWindow(v.getWindowToken(),0);
    
                        }
                    });
                    break;
            }
            return super.onOptionsItemSelected(item);
        }
    
        /**
         * 根据经纬度返回当前位置
         * @param la
         * @param lg
         */
        private void getLocationByLL(double la, double lg) {
            LatLng latLng = new LatLng(la,lg);
            //描述地图状态将要发生的变化,通过当前经纬度来使地图显示到该位置
            MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(latLng);
            mBaiduMap.setMapStatus(msu);
            getLatAndLng(la,lg);
        }
    
        /**
         * 返回当前位置的经纬度,并以闪现消息的方式显示
         */
        private void getLatAndLng(double la, double lg){
            String latAndlng = "经度:"+ String.valueOf(lg) + "
    " + "纬度:" + String.valueOf(la);
            Toast.makeText(context,latAndlng,Toast.LENGTH_LONG).show();
        }
    
    
        @Override
        protected void onStart() {
    
            super.onStart();
            //开启定位
            mBaiduMap.setMyLocationEnabled(true);
            if(!mLocationClient.isStarted()){
                mLocationClient.start();
            }
            myOrientationListener.start();
        }
        @Override
        protected void onStop() {
            super.onStop();
            //停止定位
            mBaiduMap.setMyLocationEnabled(false);
            mLocationClient.stop();
            myOrientationListener.stop();
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理
            mMapView.onDestroy();
        }
        @Override
        protected void onResume() {
            super.onResume();
            //在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理
            mMapView.onResume();
        }
        @Override
        protected void onPause() {
            super.onPause();
            //在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理
            mMapView.onPause();
        }
    
        private class MyLocationListener implements BDLocationListener{
    
            @Override
            public void onReceiveLocation(BDLocation location) {
                mLatitude = location.getLatitude();
                mLongitude = location.getLongitude();
                MyLocationData data = new MyLocationData.Builder()//
                        .direction(myCurrentX)//
                        .accuracy(location.getRadius())//
                        .latitude(mLatitude)//
                        .longitude(mLongitude).build();
                mBaiduMap.setMyLocationData(data);
                if (isFirstIn){
                    /*LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
                    MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(latLng);
                    mBaiduMap.animateMapStatus(msu);*/
                    getLocationByLL(mLatitude,mLongitude);
                    isFirstIn = false;
                    //Toast.makeText(context,location.getAddrStr(),Toast.LENGTH_LONG).show();
                }
            }
        }
    }

      (5)在MyOrientationListener中实现定位自己位置的功能,并实现地图箭头方向的指定:

    package com.example.mymap;
    
    import android.content.Context;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
    
    public class MyOrientationListener implements SensorEventListener{
        private SensorManager mSensorManager;
        private Sensor mSensor;
        private Context mContext;
        private float lastX;
        private OnOrientationListener mOnOrientationListener;
        public MyOrientationListener(Context context) {
            this.mContext = context;
        }
        //方向改变
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType()==Sensor.TYPE_ORIENTATION){
                float x=event.values[SensorManager.DATA_X];
                if(Math.abs(x-lastX)>1.0){
                    if (mOnOrientationListener!=null){
                        mOnOrientationListener.onOrientationChanged(x);
                    }
                }
                lastX=x;
            }
    
        }
    
        public void setOnOrientationListener(OnOrientationListener listener)
        {
            mOnOrientationListener=listener;
        }
    
        public void start() {
            mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
            if (mSensorManager!=null){
                //获得方向传感器
                mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
            }
            //判断是否有方向传感器
            if(mSensor!=null){
                //注册监听器
                mSensorManager.registerListener(this,mSensor,SensorManager.SENSOR_DELAY_UI);
            }
    
        }
    
        public void stop() {
            mSensorManager.unregisterListener(this);
        }
    
        public interface OnOrientationListener{
            void onOrientationChanged(float x);
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
        }
    }

      (6)在AddressToLatitudeLongitude实现具体地址向经纬度的解析:

    package com.example.mymap;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.UnsupportedEncodingException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    
    public class AddressToLatitudeLongitude {
        private String address;//地址
        private double Latitude;//纬度
        private double Longitude;//经度
    
        public AddressToLatitudeLongitude(String addr_str) {
            this.address = addr_str;
        }
    
        /**
         * 根据地址得到地理图标
         */
        public void getLatAndLngByAddress() {
            String addr = "";
            String lat = "";
            String lng = "";
            try{
                addr = java.net.URLEncoder.encode(address,"UTF-8");//设置编码
            } catch (UnsupportedEncodingException e){
                e.printStackTrace();
            }
            String url = String.format("http://api.map.baidu.com/geocoder/v2/?"
                    +"&mcode=72:2B:6A:60:DC:44:F0:0F:2A:89:12:2A:53:5B:4E:C5:85:DC:B9:2B;com.example.mymap&"
                    +"address=%s&ak=LXlkwMMGlu1fTWqxQRSaaixl6XcIjL3c&output=json",addr);
            URL myURL = null;
            URLConnection httpsConn = null;
            //进行转码
            try{
                myURL = new URL(url);
    
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
            try {
                httpsConn = (URLConnection)myURL.openConnection();//建立连接
                if (httpsConn != null){
                    InputStreamReader insr = new InputStreamReader(
                            httpsConn.getInputStream(),"UTF-8");
                    BufferedReader br = new BufferedReader(insr);
                    String data = null;
                    if((data = br.readLine())!=null){
                        System.out.println(data);
                        lat = data.substring(data.indexOf(""lat":")+(""lat":").length(), data.indexOf("},"precise""));
                        lng = data.substring(data.indexOf(""lng":")+(""lng":").length(), data.indexOf(","lat""));
                    }
                    insr.close();
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            this.Latitude = Double.parseDouble(lat);
            this.Longitude = Double.parseDouble(lng);
        }
    
        public double getLatitude() {
            return Latitude;
        }
    
        public double getLongitude() {
    
            return Longitude;
        }
     
    }

      (7)对于一些在地图中可能用的图片等资源,暂时存储到res文件夹下的drawable里面。

    4.项目演示:

      完成以上内容之后就可以在真机上进行调试,运行项目代码并演示:

      初始定位:                                                     实现功能:                                             

                            

       输入地址搜索,定位到该位置并显示经纬度:                                                        返回当前位置:

                                   

    至此整个项目结束。

    5.参考文章:

      https://www.imooc.com/learn/238(慕课网—百度地图在Android中的使用)

      https://blog.csdn.net/wl1710582732/article/details/73466031(实现定位)

      https://blog.csdn.net/xfhy_/article/details/52535436(地址与经纬度转换)

      https://blog.csdn.net/need_just_word/article/details/78026057(解决线程中toast闪退的问题)

  • 相关阅读:
    数据提交方式:post和get
    什么是SQL注入式攻击和如何防范?
    CSS3 @keyframes 规则
    php数据库连接及简单操作
    深入理解CSS过渡transition
    css 选择器
    利用border制作三角形原理
    iOS 8 自适应 Cell
    dSYM 文件分析工具
    iOS开发使用半透明模糊效果方法整理
  • 原文地址:https://www.cnblogs.com/yunkaiL/p/10134456.html
Copyright © 2011-2022 走看看