基於百度定位SDK的定位服務的實現

 

轉載請標明出處:http://blog.csdn.net/android_ls/article/details/10179013html

1、定位模塊的需求:咱們想知道使用咱們應用的用戶的大概位置,每隔五分鐘上傳一次用戶當前所在地的經緯度值到服務器端。 java

2、需求分析android

     A、UML流程圖以下:git

    B、定位服務,功能具體分析:緩存

      啓動方式:手動、開機自啓動。
      關閉方式:用戶在設置裏強制中止應用、關閉手機。(用戶使用其餘軟件殺死掉咱們的服務,用戶從新啓動應用服務纔會開啓。)
      一、開機自啓動服務,等1分鐘後開始檢測網絡狀態和GPS是否開啓,並經過通知欄提醒用戶。(未開啓時,提醒三次,5分鐘提醒一次)
      二、直接啓動應用,當即開始檢測網絡狀態和GPS是否開啓,並經過彈Dialog提示用戶。若用戶不肯意開啓網絡,即網絡不可用時,直接退出應用。
     三、用戶在設置-->應用程序-->正在運行的服務裏面手動中止掉服務後,服務自動重啓。
     四、網絡檢測可用,開始檢測GPS。用戶不開啓GPS時,使用基站定位(WLAN、3G/2G)。
     五、網絡檢測可用,啓動百度地圖定位服務,每隔五分鐘確認一次當前我所在的位置,並將經緯度值上傳服務器端。
     六、網絡檢測可用,可是在發送定位數據時,網絡斷開了,以Toast形式提醒用戶。
     七、網絡檢測可用,可是在定位過程當中,網絡斷開了,而且目前打開的不是咱們的應用(也就是說服務在後臺運行),以通知的形式提醒用戶。
     八、服務運行過程當中,意外中止了。當用戶重啓應用後,服務從新啓動。
     九、添加了開機自啓動後,檢測網絡和經過通知欄提醒用戶當前的網絡、GPS狀態。
    十、服務運行過程當中,網絡檢測返回的標識的處理。
服務器

3、編碼實現:網絡

      完整源碼下載地址:http://download.csdn.net/detail/android_ls/5993623核心類的源碼以下,app

      A、服務類的源碼以下:ide

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>



      前段時間因爲忙於公司的項目,因此很久沒更新博客了,後面我會繼續更新的,謝謝你們的支持!  

相關文章
相關標籤/搜索