转载请标明出处: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("\n error code : ");
sb.append(locType);
sb.append("\n latitude : ");
sb.append(longitude);
sb.append("\n 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 + "\t 时间:" + 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>

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

基于百度定位SDK的定位服务的实现的更多相关文章

  1. Android定位&地图&导航——基于百度地图实现的定位功能

    一.问题描述 LBS位置服务是android应用中重要的功能,应用越来越广泛,下面我们逐步学习和实现lbs相关的应用如定位.地图.导航等,首先我们看如何基于百度地图实现定位功能 二.配置环境 1.注册 ...

  2. android使用百度地图SDK获取定位信息

    本文使用Android Studio开发. 获取定位信息相对简单.我们仅仅须要例如以下几步: 第一步,注冊百度账号,在百度地图开放平台新建应用.生成API_KEY.这些就不细说了,请前往这里:titl ...

  3. 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(2)-查询实现

    在上一篇博客中,我们准备好了数据.现在数据已经以我们需要的格式,存放在Elasticsearch中了. 本文讲述如何在Elasticsearch中进行空间GEO查询和聚合查询,以及如何准备ajax接口 ...

  4. 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(1)

    本文描述了一个系统,功能是评价和抽象地理围栏(Geo-fencing),以及监控和分析核心地理围栏中业务的表现. 技术栈:Spring-JQuery-百度地图WEB SDK 存储:Hive-Elast ...

  5. android 基于百度地图api开发定位以及获取详细地址

    一:百度地图开发必须要到百度开发平台android开发api下载相应的库,已经申请百度地图开发key. 二:新建项目baidumaplocation.设计main.xml文件这里注意的是MapView ...

  6. 基于百度地图SDK和Elasticsearch GEO查询的地理围栏分析系统(3)-前端实现

    转载自:http://www.cnblogs.com/Auyuer/p/8086975.html MoonLight可视化订单需求区域分析系统实现功能: 在现实生活中,计算机和互联网迅速发展,人们越来 ...

  7. AndroidBDMap学习01:基于百度地图SDK的配置以及利用API实现一个简单的地图应用

    (一)注册并获取AK码: step1:找到keytool工具,并转移到.android目录下.(前提是已经安装了java jre/jdk)  为避免有些情况,在控制台无法找到keytool,可以把与k ...

  8. Android根据baidu Android定位SDK实现定位

    参考: http://www.open-open.com/lib/view/open1346982366162.html http://api.map.baidu.com/lbsapi/cloud/g ...

  9. Android使用百度定位SDK 方法及错误处理

    之前我的项目中的位置定位使用的是基站方法,使用的Google提供的API,但是前天中午突然就不返回数据了,到网上搜了一下才知道,Google的接 口不提供服务了,基于时间紧迫用了百度现有的SDK,但是 ...

随机推荐

  1. ES6的let命令实现猜想

    今天看了看阮一峰的<ECMAScript 6入门>的let和const命令,看完let之后自己测试了一把,仿佛处在云里雾里之中.代码如下: "use strict"; ...

  2. LDAP7卸载

    3 Uninstalling Directory Server Enterprise Edition This chapter provides instructions for uninstalli ...

  3. 巧用hidden传递参数

  4. MVC+MEF+UnitOfWork+EF架构,网站速度慢的原因总结!(附加ANTS Memory Profiler简单用法)

    (最近使用内存分析工具ANTS Memory Profiler,以及其他网友提供的意见发现最终导致内存泄漏的就是MEF,在此特地更新下,与大家分享!最下面红色字体) 最近参考使用了郭明峰的一套架构来做 ...

  5. [原创] SQLite数据库使用清单(上)

    1. 介绍 1.1 安装 访问 SQLite 下载页面,从 Windows 区下载预编译的二进制文件. 您需要下载 sqlite-shell-win32-*.zip 和 sqlite-dll-win3 ...

  6. 在java中使用 File.renameTo(File)实现重命名.

    Here is part of my files: [北京圣思园Java培训教学视频]Java.SE.前9日学习成果测试题(2010年12月2日).rar [北京圣思园Java培训教学视频]Java. ...

  7. 介绍一个小工具 Linqer

    http://www.cnblogs.com/huangxincheng/archive/2011/05/12/2044990.html

  8. ui线程和后台线程异步

    private void Button_Click(object sender, RoutedEventArgs e) { CreateElementOnSeperateThread(() => ...

  9. Gprinter Android SDK V1.0 使用说明

    佳博打印机代理商淘宝店https://shop107172033.taobao.com/index.htm?spm=2013.1.w5002-9520741823.2.Sqz8Pf 在此店购买的打印机 ...

  10. JavaScript学习笔记--ES6学习(五) 数值的扩展

    ES6 对于数值类型 (Number) 进行了一下扩展: 1.对于二进制和八进制提供了新的写法 ES6对于二进制和八进制的数值提供了新的写法,分别用0b (或者0B) 和0o (或者0o) 表示.例如 ...