需求: 启动后, 就启动服务, 周期性定位, 定位后, 退出服务.
为了加快定位, 下载星历数据.
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.qti.factory.GPS;
import android.app.Service;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
//import org.apache.http.client.HttpClient;
//import org.apache.http.client.methods.HttpGet;
//import org.apache.http.impl.client.DefaultHttpClient;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import android.os.Bundle;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.annotation.WorkerThread;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
/**
* A class to monitor gps connectivity for a period of time.
* <p/>
* Once it is enabled, this will send a request to start Sevice every interval and record
* location. The latency history can be retrieved by {@link GPSMonitorService#getData(Context)}.
* This class is used to support "startMonitor" and "stopMonitor" commands.
* <p/>
*/
public class GPSMonitorService extends Service {
private static final String TAG = GPSMonitorService.class.getSimpleName();
public static final String PACKAGE_NAME = "com.qti.factory.GPS.GPSMonitorService";
public static final String ACTION_START_GPS = PACKAGE_NAME + ".START";
public static final String ACTION_STOP_GPS = PACKAGE_NAME + ".STOP";
// public static final String EXTRA_URL_TO_CHECK = "urlToCheck";
private static final String DATA_FILE = "monitor.dat";
private static final long MAX_DATA_FILE_SIZE = 1024 * 1024;
//服务的生命是1分, 间隔启动服务是2分
private static final long SERVICE_LIFE = 60 * 1000;
private static final long SERVICE_START_TIMER = 2 * 60 * 1000;
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
if (((int)msg.arg2) == 100) {
stopSelf(msg.arg1);
}
else {
onHandleIntent((Intent)msg.obj, (int)msg.arg1);
// stopSelf(msg.arg1);
}
}
}
private GpsStatus mGpsStatus;
private Iterable<GpsSatellite> mSatellites;
List<String> satelliteList = new ArrayList<String>();
LocationManager mLocationManager = null;
private Context mContext = null;
GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int arg0) {
switch (arg0) {
case GpsStatus.GPS_EVENT_STARTED:
break;
case GpsStatus.GPS_EVENT_STOPPED:
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
Log.d(TAG,"GPS_EVENT_FIRST_FIX ");
break;
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
mGpsStatus = mLocationManager.getGpsStatus(null);
mSatellites = mGpsStatus.getSatellites();
Iterator<GpsSatellite> it = mSatellites.iterator();
int count = 0;
while (it.hasNext()) {
GpsSatellite gpsS = (GpsSatellite) it.next();
if(gpsS.getSnr() > 1.0){
Log.d(TAG,"GPS_EVENT_SATELLITE_STATUS " + "Prn:" + gpsS.getPrn() + " Snr:"
+ gpsS.getSnr());
}
}
break;
default:
break;
}
}
};
LocationListener mLocationListener = new LocationListener() {
public void onLocationChanged(Location location) {
//setLocationView(location);
Log.d(TAG,"onLocationChanged " + location);
monitor(location);
stopGPS();
disable(mContext);
}
public void onProviderDisabled(String provider) {
Log.d(TAG,"onProviderDisabled " + provider);
}
public void onProviderEnabled(String provider) {
Log.d(TAG,"onProviderEnabled " + provider);
}
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d(TAG,"onStatusChanged " + provider + ", status=" + status);
}
};
/**
* Constructor.
*/
public GPSMonitorService() {
// super(GPSMonitorService.class.getSimpleName());
super();
mName = GPSMonitorService.class.getSimpleName();
mContext = this;
Log.d(TAG,"GPSMonitorService Constructor");
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
// 为服务启动一个线程, 自带looper
HandlerThread thread = new HandlerThread("GPSMonitorService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/*
IntentService在自己本身的onHandleIntent()方法里面开始执行这个任务,任务结束之后,
不需要使用stopService()方法来停止这个服务,因为IntentService会自动停止这个Service
*/
protected void onHandleIntent(Intent intent, int startID) {
final String action = intent.getAction();
Log.d(TAG,"onHandleIntent " + intent + "-- action= " + action);
if(mLocationManager == null) {
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Log.d(TAG,"mLocationManager init");
}
if (action == null || action.equals(ACTION_START_GPS)) {
startGPS(startID);
} else if (action.equals(ACTION_STOP_GPS)) {
stopGPS();
}
}
private static String getStringExtra(Intent intent, String name, String defValue) {
if (intent.hasExtra(name)) {
return intent.getStringExtra(name);
}
return defValue;
}
private void monitor(Location location) {
FileOutputStream out = null;
Log.d(TAG,"monitor--save to file");
try {
final File file = getFileStreamPath(DATA_FILE);
if (MAX_DATA_FILE_SIZE < file.length()) {
clearData(this);
}
if(file != null )
Log.d(TAG, "data file file.getAbsolutePath()=" + file.getAbsolutePath());
out = openFileOutput(DATA_FILE, Context.MODE_APPEND);
final PrintWriter writer = new PrintWriter(out);
// 把结果写到文件
writer.write(String.format("%s,", location));
writer.flush();
} catch (final Exception e) {
// Catching exceptions to prevent crash and minimize impacts on running tests.
Log.e(TAG, "failed to monitor network latency", e);
} finally {
closeSilently(out);
}
}
private void startGPS(int startID) {
if (mLocationManager
.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) {
String provider = "gps";
Log.d(TAG,"startGPS");
mLocationManager.requestLocationUpdates(provider, 1000, 0,
mLocationListener);
mLocationManager.addGpsStatusListener(gpsStatusListener);
}
// 埋雷, 1分钟后, stop掉这个service
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startID;
msg.arg2 = 100;
// 1 min lifecycle
mServiceHandler.sendMessageDelayed(msg, SERVICE_LIFE);
}
private void stopGPS() {
try {
mLocationManager.removeUpdates(mLocationListener);
mLocationManager.removeGpsStatusListener(gpsStatusListener);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
/**
* Clears the latency history data.
*
* @param context a {@link Context} object.
*/
private static void clearData(final Context context) {
context.deleteFile(DATA_FILE);
FileOutputStream out = null;
try {
out = context.openFileOutput(DATA_FILE, 0);
} catch (final Exception e) {
Log.e(TAG, e.toString());
} finally {
closeSilently(out);
}
}
/**
* Enables gps monitoring. This will also clear the latency history data.
*
* @param context a {@link Context} object.
* @param interval an interval of connectivity checks in milliseconds.
* @param urlToCheck a URL to check.
*/
public static void enable(final Context context) {
// 毫秒 , 间隔2分钟启动一次
long interval = SERVICE_START_TIMER;
Log.d(TAG,"enable");
// Clear the data file.
clearData(context);
//启动服务, 每次都会新建一个服务,是否需要优化下?
final Intent intent = new Intent(context, GPSMonitorService.class);
final PendingIntent operation = PendingIntent.getService(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager alarm = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME, interval, interval, operation);
}
/**
* Disables gps monitoring.
*
* @param context a {@link Context} object.
*/
public static void disable(final Context context) {
Log.d(TAG,"disable");
final Intent intent = new Intent(context, GPSMonitorService.class);
final PendingIntent operation = PendingIntent.getService(context, 0, intent, 0);
final AlarmManager alarm = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
alarm.cancel(operation);
}
/**
* Returns the latency history data.
*
* @param context a {@link Context} object.
* @returns a comma-separated list of latency history for gps
*/
public static String getData(final Context context) {
String output = "";
FileInputStream in = null;
try {
in = context.openFileInput(DATA_FILE);
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
output = reader.readLine();
} catch (final IOException e) {
// swallow
Log.e(TAG, e.toString());
} finally {
closeSilently(in);
}
return output;
}
private static void closeSilently(Closeable closable) {
if (closable != null) {
try {
closable.close();
} catch (final IOException e) {
// swallow
}
}
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Log.d(TAG,"onStart " + intent);
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return 2;
}
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
mServiceLooper.quit();
Log.d(TAG,"onDestroy");
}
}