zoukankan      html  css  js  c++  java
  • 基于百度定位SDK的定位服务的实现

     

    转载请标明出处:http://blog.csdn.net/android_ls/article/details/10179013

    一、定位模块的需求:我们想知道使用我们应用的用户的大概位置,每隔五分钟上传一次用户当前所在地的经纬度值到服务器端。

    二、需求分析

         A、UML流程图如下:

        B、定位服务,功能具体分析:

          启动方式:手动、开机自启动。
          关闭方式:用户在设置里强制停止应用、关闭手机。(用户使用其他软件杀死掉我们的服务,用户重新启动应用服务才会开启。)
          1、开机自启动服务,等1分钟后开始检测网络状态和GPS是否开启,并通过通知栏提醒用户。(未开启时,提醒三次,5分钟提醒一次)
          2、直接启动应用,立即开始检测网络状态和GPS是否开启,并通过弹Dialog提示用户。若用户不愿意开启网络,即网络不可用时,直接退出应用。
         3、用户在设置-->应用程序-->正在运行的服务里面手动停止掉服务后,服务自动重启。
         4、网络检测可用,开始检测GPS。用户不开启GPS时,使用基站定位(WLAN、3G/2G)。
         5、网络检测可用,启动百度地图定位服务,每隔五分钟确认一次当前我所在的位置,并将经纬度值上传服务器端。
         6、网络检测可用,但是在发送定位数据时,网络断开了,以Toast形式提醒用户。
         7、网络检测可用,但是在定位过程中,网络断开了,并且目前打开的不是我们的应用(也就是说服务在后台运行),以通知的形式提醒用户。
         8、服务运行过程中,意外停止了。当用户重启应用后,服务重新启动。
         9、添加了开机自启动后,检测网络和通过通知栏提醒用户当前的网络、GPS状态。
        10、服务运行过程中,网络检测返回的标识的处理。

    三、编码实现:

          完整源码下载地址:http://download.csdn.net/detail/android_ls/5993623核心类的源码如下,

          A、服务类的源码如下:

    package com.android.mobile.locator;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    
    import com.android.mobile.locator.net.HttpRequester;
    import com.android.mobile.locator.utils.Constant;
    import com.android.mobile.locator.utils.FileUtil;
    import com.android.mobile.locator.utils.GPSUtil;
    import com.android.mobile.locator.utils.LogUtil;
    import com.android.mobile.locator.utils.NetWorkUtil;
    import com.android.mobile.locator.utils.NotificationUtil;
    import com.android.mobile.locator.utils.ServiceUtil;
    import com.baidu.location.BDLocation;
    import com.baidu.location.BDLocationListener;
    import com.baidu.location.LocationClient;
    import com.baidu.location.LocationClientOption;
    import com.easi.mobile.locator.R;
    
    /**
     * 类名:MobileLocatorService
     * 功能描述:定位服务类。
     * @author android_ls
     * 创建日期:2013-2-18
     */
    public class MobileLocatorService extends Service {
    
        /**
         * Service action.
         */
        public static final String ACTION_MOBILE_LOCATOR_SERVICE = "com.easi.mobile.locator.MobileLocatorService";
    
        /**
         * 间隔时间5分钟
         */
         private static final int DELAY_TIME = 5*60*1000;
    
        /**
         * 开机一分钟后开始检测网络
         */
        private static final int CHECK_NETWORK_DELAY_TIME = 1 * 60 * 1000;
    
        private Context mContext;
    
        /**
         * 定位SDK的核心类
         */
        private LocationClient mLocationClient;
    
        /**
         * 定位结果处理器 # class MyLocationListener implements BDLocationListener{}
         */
        private MyLocationListener mLocationListener;
    
        /**
         * 通知工具类
         */
        private NotificationUtil mNotificationUtil;
    
        /**
         * 服务的启动方式,开机自启动/手动启动
         */
        private int startingMode = -1;
    
        /**
         * 当前网络是否可用的标志
         */
        private boolean isOpenNetwork = false;
    
        /**
         * 检测网络的次数(5分钟一次,检测三次)
         */
        private int checkNetworkNumber = 0;
    
        /**
         * 定时器
         */
        private Timer mTimer;
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            LogUtil.e("--------------MobileLocatorService onCreate()----------------");
    
            mNotificationUtil = new NotificationUtil(this);
    
            mContext = MobileLocatorService.this;
    
            // 设置为前台进程,尽量避免被系统干掉。
            // MobileLocatorService.this.setForeground(true);
    
            // 初始化定位服务,配置相应参数
            initLocationService();
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            LogUtil.e("--------------MobileLocatorService onStartCommand()----------------");
    
            if (intent != null) {
                startingMode = intent.getIntExtra("startingMode", -1);
                LogUtil.i("startingMode = " + startingMode);
                if (startingMode == Constant.HANDLER_START_SERVICE) {
    
                    LogUtil.e("-------------手动启动---------------");
                    
                    // 判断服务是否已开启
                    boolean isRun = ServiceUtil.isServiceRun(getApplicationContext(), "com.baidu.location.f");
                    LogUtil.i("isRun = " + isRun);
                    if (isRun == false) {
                        LogUtil.e("MobileLocatorService start Location Service");
    
                        // 没启动,开启定位服务
                        mLocationClient.start();
                    }
                } else {
                    // 关闭手机,再次开启手机。这种情况下,startingMode的值获取不到。
                    // 关机重启,这种情况下,startingMode的值可以拿到。
                    // if (startingMode == Constant.BOOT_START_SERVICE) {
    
                    LogUtil.e("-------------开机自启动---------------");
    
                    checkNetworkNumber++;
    
                    // 第一次,1分钟后检测网络
                    mHandler.postDelayed(new Runnable() {
    
                        @Override
                        public void run() {
    
                            LogUtil.e("--------------第一次检测网络---------------");
    
                            checkNetwork();
    
                            Message msg = new Message();
                            msg.arg1 = Constant.CHECK_NETWORK_CONNECT_FLAG;
                            mHandler.sendMessage(msg);
    
                        }
                    }, CHECK_NETWORK_DELAY_TIME);
    
                }
    
            }
    
            return Service.START_REDELIVER_INTENT;
        }
    
        /**
         * 检测网络是否可用
         */
        private void checkNetwork() {
            // 如果网络不可用,开启GPS就没有意义
            if (NetWorkUtil.isNetworkAvailable(mContext)) {
                isOpenNetwork = true;
    
                if (GPSUtil.isOPen(mContext) == false) {
                    // 通知用户GPS未开启
                    mNotificationUtil.sendGPSNotification();
                }
    
                LogUtil.i("MobileLocatorService start Location Service");
    
                // 开启定位服务
                mLocationClient.start();
    
            } else {
                // 通知用户网络不可用
                mNotificationUtil.sendNetworkNotification();
            }
        }
    
        /**
         * 初始化定位服务,配置相应参数
         */
        private void initLocationService() {
            mLocationClient = new LocationClient(this.getApplicationContext());
            mLocationListener = new MyLocationListener();
            mLocationClient.registerLocationListener(mLocationListener);
    
            LocationClientOption locationOption = new LocationClientOption();
            locationOption.setOpenGps(true);
            locationOption.setCoorType("bd09ll");
            locationOption.disableCache(true);
            locationOption.setPriority(LocationClientOption.GpsFirst);
            locationOption.setScanSpan(DELAY_TIME);
            locationOption.setProdName(this.getString(R.string.loaction_prod_name));
    
            mLocationClient.setLocOption(locationOption);
        }
    
        Handler mHandler = new Handler() {
    
            @Override
            public void handleMessage(Message msg) {
                int result = msg.arg1;
    
                switch (result) {
                case Constant.CHECK_NETWORK_CONNECT_FLAG:
    
                    // 第一检测网络,直接过了。(已打开)
                    boolean isRun = ServiceUtil.isServiceRun(getApplicationContext(), "com.baidu.location.f");
                    LogUtil.i("isRun = " + isRun);
                    if (isOpenNetwork && isRun) {
                        LogUtil.i("--------------第一次检测网络,直接过了。(已打开)----------------");
                        return;
                    }
    
                    mTimer = new Timer();
                    mTimer.schedule(new TimerTask() {
    
                        @Override
                        public void run() {
                            checkNetworkNumber++;
                            LogUtil.i("Timer checkNetworkNumber = " + checkNetworkNumber);
    
                            checkNetwork();
    
                            boolean isRun = ServiceUtil.isServiceRun(getApplicationContext(), "com.baidu.location.f");
                            if (isOpenNetwork && isRun) {
                                mNotificationUtil.cancelNotification(Constant.NOTIFICATIO_NETWORK_NOT_OPEN);
                                mTimer.cancel();
                                return;
                            } else {
                                if (checkNetworkNumber == 3) {
    
                                    LogUtil.e("--------------第三次检测网络,还未开启,直接退出应用---------");
    
                                    // 检查网络,提醒了用户三次依然未开,退出应用。
                                    mNotificationUtil.cancelNotification(Constant.NOTIFICATIO_NETWORK_NOT_OPEN);
                                    mNotificationUtil.cancelNotification(Constant.NOTIFICATIO_GPS_NOT_OPEN);
                                    mTimer.cancel();
    
                                    // System.gc();
                                    System.exit(0);
                                }
                            }
                        }
                    }, 0, DELAY_TIME);
    
                    break;
    
                case Constant.UPLOAD_LOACTION_SUCCESS:
                    LogUtil.i("您当前的位置上传服务器成功!");
                    // Toast.makeText(getApplicationContext(), "您当前的位置上传服务器成功!", Toast.LENGTH_LONG).show();        
                    break;
    
                case Constant.LOCATION_NETWORK_EXCEPTION:
                    LogUtil.e("网络异常!请检查您的网络连接。");
                    //  网络异常,没有成功向服务器发起请求。
                    // Toast.makeText(getApplicationContext(), "网络异常!请检查您的网络连接。", Toast.LENGTH_LONG).show();
    
                    // 通知用户网络不可用
                    mNotificationUtil.sendNetworkNotification();
                    break;
    
                case Constant.LOCATION_NETWORK_CONNECT_FAIL:
                    LogUtil.e("网络连接失败,请将网络关闭再重新打开试试!");
    
                    // 通知用户网络不可用
                    mNotificationUtil.sendNetworkNotification();
                    break;
    
                case Constant.UPLOAD_LOACTION_FAIL:
                    // Toast.makeText(getApplicationContext(), "您当前的位置上传服务器失败!请查看下你的网络状态。", Toast.LENGTH_LONG).show();
                    LogUtil.e("您当前的位置上传服务器失败!");
                    break;
    
                default:
                    break;
                }
            }
        };
    
        
        class MyLocationListener implements BDLocationListener {
            double longitude;
    
            double latitude;
    
            @Override
            public void onReceiveLocation(BDLocation location) {
                if (location == null) {
                    return;
                }
    
                LogUtil.i("BDLocationListener onReceiveLocation()");
    
                /* location.getLocType()的返回值含义:
                   61 : GPS定位结果
                   62 : 扫描整合定位依据失败。此时定位结果无效。
                   63 : 网络异常,没有成功向服务器发起请求。此时定位结果无效。
                   65 : 定位缓存的结果。
                   66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果
                   67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果
                   68 : 网络连接失败时,查找本地离线定位时对应的返回结果
                   161: 表示网络定位结果
                   162~167: 服务端定位失败。*/
                int locType = location.getLocType();
    
                longitude = location.getLongitude();
                latitude = location.getLatitude();
    
                // TODO 调试使用
                StringBuffer sb = new StringBuffer(256);
                sb.append(" time : ");
                sb.append(location.getTime());
                sb.append("
     error code : ");
                sb.append(locType);
                sb.append("
     latitude : ");
                sb.append(longitude);
                sb.append("
     longitude : ");
                sb.append(latitude);
                LogUtil.i("BDLocationListene " + sb.toString());
    
                if (locType == Constant.LOCATION_GPS || locType == Constant.LOCATION_NETWORK) {
    
                     //  GPS定位结果、网络定位结果
                     mHandler.post(new Runnable() {
    
                         @Override
                         public void run() {
                             String userId = "bgao";
                             int result = send(userId, longitude, latitude);
                             
                             Message msg = new Message();
                             msg.arg1 = result;
                             mHandler.sendMessage(msg);
                         }
                     });
    
                } else if (locType == Constant.LOCATION_NETWORK_EXCEPTION || locType == Constant.LOCATION_NETWORK_CONNECT_FAIL) {
                    //  网络异常,没有成功向服务器发起请求。
                    Message msg = new Message();
                    msg.arg1 = locType;
                    mHandler.sendMessage(msg);
                }
            }
    
            @Override
            public void onReceivePoi(BDLocation arg0) {
    
            }
        }
    
        /**
         * 向服务器端当前位置的经纬度
         * @param usetId 用户ID
         * @param longitude 经度值
         * @param latitude 纬度值
         */
        private int send(String usetId, double longitude, double latitude) {
            StringBuffer params = new StringBuffer();
            params.append("event=save");
            params.append("¤tPointX=");
            params.append(longitude);
            params.append("¤tPointY=");
            params.append(latitude);
            params.append("&userId=");
            params.append(usetId);
    
            try {
                InputStream inputStream = HttpRequester.post(Constant.UPLOAD_GPS_URL, params);
                if (inputStream != null) {
                    String result = new String(FileUtil.read(inputStream));
                    String time = (new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss")).format(System.currentTimeMillis());
                    LogUtil.e("网络请求返回的结果:result = " + result + "	 时间:" + time);
    
                    if ("Y".equals(result)) {
                        return 1;
                    } else if ("N".equals(result)) {
                        return 0;
                    } else {
                        LogUtil.e("服务器端返回的值与预先商定的不否! ");
                    }
                } else {
                    LogUtil.e("网络请求成功,但是返回的数据流为NULL");
                }
            } catch (IOException e) {
                LogUtil.e("IOException 服务器访问失败!");
                e.printStackTrace();
                return 0;
            }
    
            return 0;
        }
    
        @Override
        public void onDestroy() {
            LogUtil.e("---------------MobileLocatorService onDestroy()----------------");
    
            if (mLocationClient != null && mLocationClient.isStarted()) {
                mLocationClient.stop();
                if (mLocationListener != null) {
                    mLocationClient.unRegisterLocationListener(mLocationListener);
                }
            }
    
            SharedPreferences sp = mContext.getSharedPreferences("MobileLocator", Context.MODE_PRIVATE);
            String result = sp.getString("instruct", null);
            LogUtil.i("MobileLocatorService onDestroy() result = " + result);
            if ("exit".equals(result)) {
                sp.edit().putString("instruct", "true").commit();
                LogUtil.e("---------------MobileLocatorService onDestroy()-----------1-----");
                System.exit(0);
                return;
            }
    
            LogUtil.e("---------------MobileLocatorService onDestroy()---------2-------");
    
            // 销毁时重新启动Service
            Intent intent = new Intent(ACTION_MOBILE_LOCATOR_SERVICE);
            intent.putExtra("startingMode", startingMode);
            this.startService(intent);
        }
    
    }
    

           B、启动时系统发出的广播的接收器类源码:

    package com.android.mobile.locator;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    
    import com.android.mobile.locator.utils.Constant;
    import com.android.mobile.locator.utils.LogUtil;
    
    /**
     * 类名:BootBroadcastReceiver 
     * 功能描述:启动时系统发出的广播的接收器
     * #<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     * @author android_ls
     */
    public class BootBroadcastReceiver extends BroadcastReceiver {
    
    	private static final String ACTION_BOOT = "android.intent.action.BOOT_COMPLETED";
    
    	@Override
    	public void onReceive(Context context, Intent intent) {
    	    LogUtil.i("Boot this system , BootBroadcastReceiver onReceive()");
    		
    		if (intent.getAction().equals(ACTION_BOOT)) {
    		    LogUtil.i("BootBroadcastReceiver onReceive(), MobileLocatorService Start");
    		    
    		    Intent mIntent = new Intent(MobileLocatorService.ACTION_MOBILE_LOCATOR_SERVICE);
    		    mIntent.putExtra("startingMode", Constant.BOOT_START_SERVICE);
    			context.startService(mIntent);
    		}
    
    	}
    
    }
    

          C、关机时系统发出的广播的接收器类源码:

    package com.android.mobile.locator;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences;
    
    import com.android.mobile.locator.utils.LogUtil;
    
    /**
     * 类名:ShutdownBroadcastReceiver
     * 功能描述:关机时系统发出的广播的接收器
     * @author android_ls
     */
    public class ShutdownBroadcastReceiver extends BroadcastReceiver {
    
    	private static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
    	
    	@Override
    	public void onReceive(Context context, Intent intent) {
    	    LogUtil.e("Shut down this system, ShutdownBroadcastReceiver onReceive()");
    	    
    		if (intent.getAction().equals(ACTION_SHUTDOWN)) {
    		    LogUtil.i("ShutdownBroadcastReceiver onReceive(), MobileLocatorService Stop");
    		    
    		    SharedPreferences sp = context.getSharedPreferences("MobileLocator", Context.MODE_PRIVATE);
    		    sp.edit().putString("instruct", "exit").commit();
    		    
    			context.stopService(new Intent(MobileLocatorService.ACTION_MOBILE_LOCATOR_SERVICE));
    		}
    
    	}
    
    }
    

           D、在AndroidManifest.xml文件中的配置:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.easi.mobile.locator"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk android:minSdkVersion="8" />
    
        <!--
        android:sharedUserId="android.uid.system"
        android:killAfterRestore="true"
        android:process=":remote"  
        android:enabled="true"
        -->
    
        <application
            android:allowClearUserData="false"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name" >
            <activity
                android:label="@string/app_name"
                android:name="com.android.mobile.locator.MobileLocatorActivity" >
                <intent-filter >
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <service
                android:enabled="true"
                android:name="com.android.mobile.locator.MobileLocatorService"
                android:process=":remote" >
                <intent-filter >
                    <action android:name="com.easi.mobile.locator.MobileLocatorService" />
                </intent-filter>
            </service>
            <service
                android:enabled="true"
                android:name="com.baidu.location.f"
                android:process=":remote" />
    
            <receiver android:name="com.android.mobile.locator.BootBroadcastReceiver" >
                <intent-filter >
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <category android:name="android.intent.category.HOME" /> 
                </intent-filter>
            </receiver>
            <receiver android:name="com.android.mobile.locator.ShutdownBroadcastReceiver" >
                <intent-filter >
                    <action android:name="android.intent.action.ACTION_SHUTDOWN" />
                    <category android:name="android.intent.category.HOME" />
                </intent-filter>
            </receiver>
        </application>
    
        <!-- 授予应用程序访问系统开机事件的权限 -->
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <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.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
        <uses-permission android:name="android.permission.READ_LOGS" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    
    </manifest>



          前段时间由于忙于公司的项目,所以好久没更新博客了,后面我会继续更新的,谢谢大家的支持!
     


     

  • 相关阅读:
    【算法】Kruskal算法(解决最小生成树问题) 含代码实现
    POJ 1182 食物链 (并查集解法)(详细注释)
    APICloud关闭Key Building Resolve
    ubuntu配置国内源
    缓存穿透、缓存击穿、缓存雪崩概念及解决方案
    POST请求和GET请求的区别
    ibatis 中#和 $ 符号的区别
    自动装箱和自动拆箱理解
    回文串算法说明(带注释)
    Object 对象有哪些方法?
  • 原文地址:https://www.cnblogs.com/james1207/p/3275448.html
Copyright © 2011-2022 走看看