編輯:關於Android編程
雖然自己已經完成了百度地圖的調用,但是在使用過程中產生很多的疑問,在不斷的百度各種大神的作品後才慢慢的調試出來,所以覺得作為新手自己應該把這個過程記錄下來。尤其是自己在找到大神的文章時,並不能理解有些單純一個方法和一個解釋,主要還是水平有限,在查資料的過程中也深知寫好一篇博文對於需要的人來說就是一汪泉水,欣喜的發現這篇博文講的有頭由尾,可以參照一步一步的來進行。記錄下來這個過程對於自己也是一種復習,比如當初費盡心思解決的難題再一年後再去看代碼卻毫無頭緒,所以這樣的記錄還是很有必要的,自己也盡力的去把每一步自己的理解寫清楚,不管是以後自己再改正或者隨著學習漸漸理解一些深層次的知識點。
好了廢話這麼多,開啟這篇文章
首先分享一個利用手機自帶GPS定位的一份代碼:
進行一個安卓應用之前要先了解安卓應用的項目的各個文件的作用,以及一些基本的操作知識
先看一下項目的文件布局

1、在AndroidManifest.xml中添加權限,具體的權限類型可以百度查詢或者api查詢
2、MainActivity.java 這個是項目的activity,裡面的代碼主要是參照某位大神的,具體的地址點擊打開鏈接
裡面講解的比較詳細,也適合像我這樣的初學者
package net.zqmc.gpstest;
import java.util.Iterator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.location.Criteria;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText editText;
private LocationManager lm;
private static final String TAG = "GpsActivity";
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
lm.removeUpdates(locationListener);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText);
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 判斷GPS是否正常啟動
if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "請開啟GPS導航...", Toast.LENGTH_SHORT).show();
// 返回開啟GPS導航設置界面
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, 0);
return;
}
// 為獲取地理位置信息時設置查詢條件
String bestProvider = lm.getBestProvider(getCriteria(), true);
// 獲取位置信息
// 如果不設置查詢要求,getLastKnownLocation方法傳人的參數為LocationManager.GPS_PROVIDER
Location location = lm.getLastKnownLocation(bestProvider);
updateView(location);
// 監聽狀態
lm.addGpsStatusListener(listener);
// 綁定監聽,有4個參數
// 參數1,設備:有GPS_PROVIDER和NETWORK_PROVIDER兩種
// 參數2,位置信息更新周期,單位毫秒
// 參數3,位置變化最小距離:當位置距離變化超過此值時,將更新位置信息
// 參數4,監聽
// 備注:參數2和3,如果參數3不為0,則以參數3為准;參數3為0,則通過時間來定時更新;兩者為0,則隨時刷新
// 1秒更新一次,或最小位移變化超過1米更新一次;
// 注意:此處更新准確度非常低,推薦在service裡面啟動一個Thread,在run中sleep(10000);然後執行handler.sendMessage(),更新位置
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, locationListener);
}
// 位置監聽
private LocationListener locationListener = new LocationListener() {
/**
* 位置信息變化時觸發
*/
public void onLocationChanged(Location location) {
updateView(location);
Log.i(TAG, "時間:" + location.getTime());
Log.i(TAG, "經度:" + location.getLongitude());
Log.i(TAG, "緯度:" + location.getLatitude());
Log.i(TAG, "海拔:" + location.getAltitude());
}
/**
* GPS狀態變化時觸發
*/
public void onStatusChanged(String provider, int status, Bundle extras) {
switch (status) {
// GPS狀態為可見時
case LocationProvider.AVAILABLE:
Log.i(TAG, "當前GPS狀態為可見狀態");
break;
// GPS狀態為服務區外時
case LocationProvider.OUT_OF_SERVICE:
Log.i(TAG, "當前GPS狀態為服務區外狀態");
break;
// GPS狀態為暫停服務時
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Log.i(TAG, "當前GPS狀態為暫停服務狀態");
break;
}
}
/**
* GPS開啟時觸發
*/
public void onProviderEnabled(String provider) {
Location location = lm.getLastKnownLocation(provider);
updateView(location);
}
/**
* GPS禁用時觸發
*/
public void onProviderDisabled(String provider) {
updateView(null);
}
};
// 狀態監聽
GpsStatus.Listener listener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int event) {
switch (event) {
// 第一次定位
case GpsStatus.GPS_EVENT_FIRST_FIX:
Log.i(TAG, "第一次定位");
break;
// 衛星狀態改變
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
Log.i(TAG, "衛星狀態改變");
// 獲取當前狀態
GpsStatus gpsStatus = lm.getGpsStatus(null);
// 獲取衛星顆數的默認最大值
int maxSatellites = gpsStatus.getMaxSatellites();
// 創建一個迭代器保存所有衛星
Iterator iters = gpsStatus.getSatellites()
.iterator();
int count = 0;
while (iters.hasNext() && count <= maxSatellites) {
GpsSatellite s = iters.next();
count++;
}
System.out.println("搜索到:" + count + "顆衛星");
break;
// 定位啟動
case GpsStatus.GPS_EVENT_STARTED:
Log.i(TAG, "定位啟動");
break;
// 定位結束
case GpsStatus.GPS_EVENT_STOPPED:
Log.i(TAG, "定位結束");
break;
}
};
};
/**
* 實時更新文本內容
*
* @param location
*/
private void updateView(Location location) {
if (location != null) {
editText.setText("設備位置信息\n\n經度:");
editText.append(String.valueOf(location.getLongitude()));
editText.append("\n緯度:");
editText.append(String.valueOf(location.getLatitude()));
} else {
// 清空EditText對象
editText.getEditableText().clear();
}
}
/**
* 返回查詢條件
*
* @return
*/
private Criteria getCriteria() {
Criteria criteria = new Criteria();
// 設置定位精確度 Criteria.ACCURACY_COARSE比較粗略,Criteria.ACCURACY_FINE則比較精細
criteria.setAccuracy(Criteria.ACCURACY_FINE);
// 設置是否要求速度
criteria.setSpeedRequired(false);
// 設置是否允許運營商收費
criteria.setCostAllowed(false);
// 設置是否需要方位信息
criteria.setBearingRequired(false);
// 設置是否需要海拔信息
criteria.setAltitudeRequired(false);
// 設置對電源的需求
criteria.setPowerRequirement(Criteria.POWER_LOW);
return criteria;
}
}
3、接下來的是layout布局,主要是講獲得的經緯度打印到手機屏幕中
全部寫完後,點擊運行,然後在模擬機上定義虛擬經緯度,或者直接用真機測試,直接真機調試還是比較方便的。
好了,接下來就來說一下百度的Android 定位sdk了,最新的版本是v5.0,但是沒有找到下載地址,估計是我沒找到,然後就看到了v4.2的,關於百度的這個sdk可以先看一下管方的解釋,以及在使用時的說明點擊打開鏈接 百度密匙的獲取方法可以參考銜接:點擊打開鏈接
【重要提醒】
定位SDKv3.1版本之後,以下權限已不需要,請取消聲明,否則將由於Android 5.0多帳戶系統加強權限管理而導致應用安裝失敗。
使用SDK5.0需要在Mainfest.xml設置Accesskey,設置有誤會引起定位和地理圍欄服務不能正常使用,必須進行Accesskey的正確設置。
設置AccessKey,在application標簽中加入
//key:開發者申請的key
MainActivity.java 因為我是在項目中調用的,所以該類中只是調用,沒有打印在屏幕中,不過我會在代碼裡注釋
package net.zmqc.infogps;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.LocationClientOption.LocationMode;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
public LocationClient mLocationClient = null;
public MyLocationListenner myListener = new MyLocationListenner();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mLocationClient = new LocationClient( this );
mLocationClient.registerLocationListener( myListener );
setLocationOption();//設定定位參數
mLocationClient.start();//開始定位
// 重新定位
if (mLocationClient != null && mLocationClient.isStarted())
{
mLocationClient.requestLocation();
Toast.makeText(MainActivity.this,"正在定位...", Toast.LENGTH_LONG).show();
}
else
Log.d("msg", "locClient is null or not started");
}
//設置相關參數
private void setLocationOption(){
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);
option.setLocationMode(LocationMode.Hight_Accuracy);//設置定位模式
option.setCoorType("gcj02");//返回的定位結果是百度經緯度,默認值gcj02
int span=30000;
option.setScanSpan(span);//設置發起定位請求的間隔時間,若無此項則只是定位一次
option.setIsNeedAddress(true);
mLocationClient.setLocOption(option);
}
@Override
public void onDestroy() {
mLocationClient.stop();//停止定位
super.onDestroy();
}
/**
* 監聽函數,有更新位置的時候,格式化成字符串
*/
public class MyLocationListenner implements BDLocationListener {
@Override
//接收位置信息
public void onReceiveLocation(BDLocation location) {
if (location == null)
return ;
location.getLatitude();//在監聽函數中可獲得經緯度,可以打印出來,或者直接通過toast查看
location.getLongitude();
Toast.makeText(MainActivity.this,"正在定位..."+location.getLatitude()+" "+location.getLongitude(), Toast.LENGTH_LONG).show();
}
//接收POI信息函數,我不需要POI,所以我沒有做處理
public void onReceivePoi(BDLocation poiLocation) {
if (poiLocation == null) {
return;
}
}
}
}
location.getLatitude(); location.getLongitude();
詳細可以查看一篇查看文章點擊打開鏈接
項目中使用地圖定位,然後再根據經緯度計算兩點之間的距離,分享一個計算兩點之間距離的函數
package net.zmqc.tool;
public class DistanceCom {
public static double computeDistance(double lat1, double lon1,
double lat2, double lon2) {
// Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
// using the "Inverse Formula" (section 4)
int MAXITERS = 20;
// Convert lat/long to radians
lat1 *= Math.PI / 180.0;
lat2 *= Math.PI / 180.0;
lon1 *= Math.PI / 180.0;
lon2 *= Math.PI / 180.0;
double a = 6378137.0; // WGS84 major axis
double b = 6356752.3142; // WGS84 semi-major axis
double f = (a - b) / a;
double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
double L = lon2 - lon1;
double A = 0.0;
double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
double cosU1 = Math.cos(U1);
double cosU2 = Math.cos(U2);
double sinU1 = Math.sin(U1);
double sinU2 = Math.sin(U2);
double cosU1cosU2 = cosU1 * cosU2;
double sinU1sinU2 = sinU1 * sinU2;
double sigma = 0.0;
double deltaSigma = 0.0;
double cosSqAlpha = 0.0;
double cos2SM = 0.0;
double cosSigma = 0.0;
double sinSigma = 0.0;
double cosLambda = 0.0;
double sinLambda = 0.0;
double lambda = L; // initial guess
for (int iter = 0; iter < MAXITERS; iter++) {
double lambdaOrig = lambda;
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
double t1 = cosU2 * sinLambda;
double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
double sinSqSigma = t1 * t1 + t2 * t2; // (14)
sinSigma = Math.sqrt(sinSqSigma);
cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
sigma = Math.atan2(sinSigma, cosSigma); // (16)
double sinAlpha = (sinSigma == 0) ? 0.0 :
cosU1cosU2 * sinLambda / sinSigma; // (17)
cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
cos2SM = (cosSqAlpha == 0) ? 0.0 :
cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
A = 1 + (uSquared / 16384.0) * // (3)
(4096.0 + uSquared *
(-768 + uSquared * (320.0 - 175.0 * uSquared)));
double B = (uSquared / 1024.0) * // (4)
(256.0 + uSquared *
(-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
double C = (f / 16.0) *
cosSqAlpha *
(4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
double cos2SMSq = cos2SM * cos2SM;
deltaSigma = B * sinSigma * // (6)
(cos2SM + (B / 4.0) *
(cosSigma * (-1.0 + 2.0 * cos2SMSq) -
(B / 6.0) * cos2SM *
(-3.0 + 4.0 * sinSigma * sinSigma) *
(-3.0 + 4.0 * cos2SMSq)));
lambda = L +
(1.0 - C) * f * sinAlpha *
(sigma + C * sinSigma *
(cos2SM + C * cosSigma *
(-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
double delta = (lambda - lambdaOrig) / lambda;
if (Math.abs(delta) < 1.0e-12) {
break;
}
}
return b * A * (sigma - deltaSigma);
}
}
學習Android Material Design(RecyclerView代替ListView)
本文實例實現一下 RecyclerView,代碼比較簡單,適合初學者,如有錯誤,歡迎指出。復習 ListView可以查看這篇文章深入淺出學習Android ListVie
詳解Android TabHost的多種實現方法 附源碼下載
最近仔細研究了下TabHost,主要是為了實現微信底部導航欄的功能,最後也給出一個文章鏈接,大家不要著急正文:TabHost的實現分為兩種,一個是不繼承TabActivi
UI碎片控件之Fragment——底部導航欄的實現(方法1)
(一)概述在上一節中我們對Fragment進行了一個初步的了解,學習了概念,生命周期,Fragment管理與 Fragment事務,以及動態與靜態加載Fragment。從
Android Activity與Intent詳解及示例代碼
Android有三個基礎組件Activity,Service和BroadcastReceiver,他們都是依賴Intent來啟動。本文介紹的是Activity的生命周期以