一个gps的后台定位服务, 启动周期定位

374 阅读3分钟

需求: 启动后, 就启动服务, 周期性定位, 定位后, 退出服务.

为了加快定位, 下载星历数据.

/*
 * 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");
    }


}