做应用的都应该熟悉Service这个类。Android四大组件之一。Activity的反面,没有界面,后台运行,但是它仍然是运行在主界面的。Activity退出时,Service仍可以继续执行。Service常见用于播放器,Service + Thread + Notification的模式很常见。Service也可以用来远程调用。
有一次遇到一位同事写的定位代码,他使用的service,利用service的特性,在需要定位的时候启动service进行定位。实际使用过程中,会出现这样的情况:定位工作不执行。刚开始没注意,一直以为是百度地图的问题。后来打印Log,发现Service被recycle了,因为内存吃紧,service被回收了。导致这部分工作出了问题。在这里提醒大家下,Service不一定会一直在后台执行,当内存不够时,会触发service回收,等到适当的时候,再根据service中onStartCommand( Intent intent, int flags, int startId);中的flag值进行重启动策略。
public class LocationService extends Service {
private static final String TAG = LocationService.class.getSimpleName();
private ServiceHandler mServiceHandler;
private Looper mServiceLooper;
public LocationClient locationClient;
private final int UPDATE_TIME = 3*1000;
@Override
public void onCreate() {
super.onCreate();
L.log(AppInterface.LOG_DEBUG , 0 , TAG, "onCreate");
HandlerThread thread = new HandlerThread(TAG,Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
* 开始定位
* @param context
*/
public static void startLocation(Context context){
Intent intent = new Intent(context,LocationService.class);
intent.setAction("start_location");
context.startService(intent);
}
/**
* 停止定位
* @param context
*/
public static void stopLocation(Context context){
Intent intent = new Intent(context,LocationService.class);
intent.setAction("stop_location");
context.startService(intent);
}
/**
* @param context
*/
public static void requestLocation(Context context){
Intent intent = new Intent(context,LocationService.class);
intent.setAction("request_location");
context.startService(intent);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
Intent intent = (Intent) msg.obj;
if (intent != null) {
String action = intent.getAction();
if("start_location".equals(action)){
startLocation();
}else if("stop_location".equals(action)){
stopLocation();
}else if("request_location".equals(action)){
requestLocation();
}
}
}
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
if(null != intent){
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
//被回收时,同时将intent传递进来,重启
return Service.START_REDELIVER_INTENT;
}
return super.onStartCommand(intent, flags, startId);
}
private void initLocationConfig(){
locationClient = new LocationClient(this);
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);
option.setAddrType("all");
option.setPriority(LocationClientOption.GpsFirst);
option.setCoorType(BDLocation.BDLOCATION_GCJ02_TO_BD09LL);//百度地图的二次加密
//option.setCoorType(BDLocation.BDLOCATION_BD09LL_TO_GCJ02);
option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);//高精度定位
option.setProdName(getString(R.string.app_name));
option.setScanSpan(UPDATE_TIME);
option.setIsNeedAddress(false);
option.disableCache(false);//不使用缓存定位
locationClient.setLocOption(option);
locationClient.registerLocationListener(new MyBDLocationListener());
}
private void startLocation(){
if(locationClient==null){
initLocationConfig();
}
if(!locationClient.isStarted()){
locationClient.start();
}
locationClient.requestLocation();
L.log(AppInterface.LOG_DEBUG, 0 , TAG , "the location client is start ----------");
}
private void stopLocation(){
if(locationClient!=null){
if(locationClient.isStarted()){
locationClient.stop();
L.log(AppInterface.LOG_DEBUG, 0 , TAG , "the location client is stop ----------");
}
}
}
private void requestLocation(){
if(locationClient!=null){
if(!locationClient.isStarted()){
locationClient.start();
}
locationClient.requestLocation();
L.log(AppInterface.LOG_DEBUG, 0 , TAG ,"the location client is request ----------");
}
}
private class MyBDLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation location) {
L.log(AppInterface.LOG_DEBUG, 0 , TAG ,"onReceiveLocation ----------");
if (location == null) {
locationClient.start();
locationClient.requestLocation();
return;
}
L.log(AppInterface.LOG_DEBUG, 0 , TAG , "type = " + location.getLocType() + "(gps type = " + BDLocation.TypeGpsLocation + "), latitude = " + location.getLatitude() + " , longitude = " + location.getLongitude() + " , speed = " + location.getSpeed() + " , satelite = " + location.getSatelliteNumber()+",radius = " + location.getRadius());
double latitude = location.getLatitude();
double longitude = location.getLongitude();
if((latitude >0 && latitude < 0.0000001) || (longitude >0 && longitude < 0.0000001)){
//非法的经纬度
return ;
}
String address = "";
boolean isLocationValid = false;
if(location.getLocType() == BDLocation.TypeNetWorkLocation){
if(CheckUtil.isNetworkAvailable(LocationService.this)){
isLocationValid = true;
address = location.getAddrStr();
}
} else if(location.getLocType() == BDLocation.TypeGpsLocation){
isLocationValid = true;
address = location.getAddrStr();
}
//对位置进行传递,在LocationCallBack中进行回调
LocationCallBack.getInstance(LocationService.this).setLocationData(location);
}
}
@Override
public void onDestroy() {
super.onDestroy();
stopLocation();
L.log(AppInterface.LOG_DEBUG , 0 , TAG, "onDestroy");
}
}