此實現可以在後臺持續進行定位,將經緯度信息傳給服務器或者其他操作。
在定位之前請先準備好:百度地圖定位SDK和相關權限配置(具體參照Baidu官方文檔)。
後臺持續重複定位,具體實現是通過調用自定義服務實現,在服務中創建定時器,在定時器中定時進行定位。
自定義服務,在此服務中進行定位。注意要在清單配置文件中註冊該服務。
public class LocationServices extends Service{
//定位點信息
public LatLng latlng;
private String strLocationProvince;//定位點的省份
private String strLocationCity;//定位點的城市
private String strLocationDistrict;//定位點的區縣
private String strLocationStreet;//定位點的街道信息
private String strLocationStreetNumber;//定位點的街道號碼
private String strLocationAddrStr;//定位點的詳細地址(包括國家和以上省市區等信息)
private LocationClient mLocationClient =null;//定位客戶端
public MyLocationListener mMyLocationListener = new MyLocationListener();;
private Timer mTimer = null;
private TimerTask mTimerTask = null;
private boolean isStop = false;
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
mLocationClient = new LocationClient(getApplicationContext());
mLocationClient.setLocOption(setLocationClientOption());
mLocationClient.registerLocationListener(mMyLocationListener);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 觸發定時器
if (!isStop) {
Log.i("tag", "定時器啓動");
startTimer();
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (mLocationClient!=null) {
mLocationClient.stop();
}
super.onDestroy();
// 停止定時器
if (isStop) {
Log.i("tag", "定時器服務停止");
stopTimer();
}
}
/**
* 定時器 每隔一段時間執行一次
*/
private void startTimer() {
isStop = true;//定時器啓動後,修改標識,關閉定時器的開關
if (mTimer == null) {
mTimer = new Timer();
}
if (mTimerTask == null) {
mTimerTask = new TimerTask() {
@Override
public void run() {
do {
try {
Log.d("tag", "isStop="+isStop);
Log.d("tag", "mMyLocationListener="+mMyLocationListener);
mLocationClient.start();
Log.d("tag", "mLocationClient.start()");
Log.d("tag", "mLocationClient=="+mLocationClient);
Thread.sleep(1000*3);//3秒後再次執行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} while (isStop);
}
};
}
if (mTimer != null && mTimerTask != null) {
Log.d("tag", "mTimer.schedule(mTimerTask, delay)");
mTimer.schedule(mTimerTask, 0);//執行定時器中的任務
}
}
/**
* 停止定時器,初始化定時器開關
*/
private void stopTimer() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
isStop = false;//重新打開定時器開關
Log.d("tag", "isStop="+isStop);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
/**
* 定位客戶端參數設定,更多參數設置,查看百度官方文檔
* @return
*/
private LocationClientOption setLocationClientOption() {
LocationClientOption option = new LocationClientOption();
option.setLocationMode(com.baidu.location.LocationClientOption.LocationMode.Hight_Accuracy);// 可選,默認高精度,設置定位模式,高精度,低功耗,僅設備
option.setScanSpan(1000);//每隔1秒發起一次定位
option.setCoorType("bd09ll");// 可選,默認gcj02,設置返回的定位結果座標系
option.setOpenGps(true);//是否打開gps
option.setIsNeedLocationDescribe(true);//可選,默認false,設置是否需要位置語義化結果,可以在BDLocation.getLocationDescribe裏得到該描述,不設置則在4G情況下會默認定位到“天安門廣場”
option.setIsNeedAddress(true);//可選,設置是否需要地址信息,默認不需要,不設置則拿不到定位點的省市區信息
option.setIsNeedLocationPoiList(true);//可選,默認false,設置是否需要POI結果,可以在BDLocation.getPoiList裏得到
option.setLocationNotify(true);//可選,默認false,設置是否當gps有效時按照1S1次頻率輸出GPS結果
/*可選,默認false,設置是否需要位置語義化結果,可以在BDLocation.getLocationDescribe裏得到,結果類似於“在北京天安門附近”
該參數若不設置,則在4G狀態下,會出現定位失敗,將直接定位到天安門廣場
*/
return option;
}
/**
* 定位監聽器
* @author User
*
*/
public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
if (location==null) {
return;
}
double lat = location.getLatitude();
double lng = location.getLongitude();
latlng = new LatLng(lat, lng);
//定位點地址信息做非空判斷
if ("".equals(location.getProvince())) {
strLocationProvince = "未知省";
}else {
strLocationProvince = location.getProvince();
}
if ("".equals(location.getCity())) {
strLocationCity = "未知市";
}else {
strLocationCity = location.getCity();
}
if ("".equals(location.getDistrict())) {
strLocationDistrict = "未知區";
}else {
strLocationDistrict = location.getDistrict();
}
if ("".equals(location.getStreet())) {
strLocationStreet = "未知街道";
}else {
strLocationStreet = location.getStreet();
}
if ("".equals(location.getStreetNumber())) {
strLocationStreetNumber = "";
}else {
strLocationStreetNumber =location.getStreetNumber();
}
if ("".equals(location.getAddrStr())) {
strLocationAddrStr = "";
}else {
strLocationAddrStr =location.getAddrStr();
}
//定位成功後對獲取的數據依據需求自定義處理,這裏只做log顯示
Log.d("tag", "latlng.lat="+lat);
Log.d("tag", "latlng.lng="+lng);
Log.d("tag", "strLocationProvince="+strLocationProvince);
Log.d("tag", "strLocationCity="+strLocationCity);
Log.d("tag", "strLocationDistrict="+strLocationDistrict);
// 到此定位成功,沒有必要反覆定位
// 應該停止客戶端再發送定位請求
if (mLocationClient.isStarted()) {
Log.d("tag", "mLocationClient.isStarted()==>mLocationClient.stop()");
mLocationClient.stop();
}
}
}
}
在Application中初始化SDK,如果不需要在Application中初始化,在MainActivity中setContentView方法之前初始化也可以。百度官方建議在Application中初始化。
public class MyApplication extends Application{
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
// 在使用 SDK 各組間之前初始化 context 信息,傳入 ApplicationContext
SDKInitializer.initialize(this);
}
}
在MainActivity中開啓和關閉服務。
public class MainActivity extends Activity {
private Button startService;
private Button stopService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService = (Button) findViewById(R.id.start_service);
stopService = (Button) findViewById(R.id.stop_service);
startService.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent startIntent = new Intent(MainActivity.this, LocationServices.class);
startService(startIntent);
}
});
stopService.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent stopIntent = new Intent(MainActivity.this, LocationServices.class);
stopService(stopIntent);
}
});
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
Log.d("tag", "MainActivity.onDestroy()");
Intent stopIntent = new Intent(MainActivity.this, LocationServices.class);
stopService(stopIntent);
super.onDestroy();
}
}
MainActivity.xml佈局。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.bdlocationdemo.activity.MainActivity" >
<Button
android:id="@+id/stop_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="StopService" />
<Button
android:id="@+id/start_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="77dp"
android:text="StartService" />
</RelativeLayout>
特別注意:
在清單配置文件中,需要聲明百度定位服務,這樣才能重複定位,否則服務開啓後只會執行第一次定位,後面執行的LocationClient.start();方法,都不會執行定位監聽器BDLocationListener中的代碼,這裏需要特別留意。
<!-- 註冊自己的服務 -->
<service
android:name="com.example.bdlocationdemo.services.LocationServices"
android:enabled="true"
android:exported="true" >
</service>
<!-- 必須聲明這個服務,才能在服務中定時重複定位 -->
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>