Android開發(fā)使用LocationManager實現(xiàn)定位服務(wù)

做項目需要獲取經(jīng)緯度信息炭晒,學習了下android自帶的定位API,簡單實現(xiàn)了一下酪耕,這里記錄一下酒繁。廢話不多說滓彰,先上代碼:

private String locationStr = "";
private String message = "";
private static final int REQUEST_CODE = 10;

private void getLocation() {
    if (Build.VERSION.SDK_INT >= 23) {// android6 執(zhí)行運行時權(quán)限
        if (ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    Activity#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for Activity#requestPermissions for more details.
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE);
        }
    }

    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_COARSE);//低精度,如果設(shè)置為高精度欲逃,依然獲取不了location找蜜。
    criteria.setAltitudeRequired(false);//不要求海拔
    criteria.setBearingRequired(false);//不要求方位
    criteria.setCostAllowed(true);//允許有花費
    criteria.setPowerRequirement(Criteria.POWER_LOW);//低功耗
    //獲取LocationManager
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    // 獲取最好的定位方式
    String provider = locationManager.getBestProvider(criteria, true); // true 代表從打開的設(shè)備中查找

    // 獲取所有可用的位置提供器
    List<String> providerList = locationManager.getProviders(true);
    // 測試一般都在室內(nèi),這里顛倒了書上的判斷順序
    if (providerList.contains(LocationManager.NETWORK_PROVIDER)) {
        provider = LocationManager.NETWORK_PROVIDER;
    } else if (providerList.contains(LocationManager.GPS_PROVIDER)) {
        provider = LocationManager.GPS_PROVIDER;
    } else {
        // 當沒有可用的位置提供器時稳析,彈出Toast提示用戶
        Toast.makeText(this, "Please Open Your GPS or Location Service", Toast.LENGTH_SHORT).show();
        return;
    }

    LocationListener locationListener = new LocationListener(){
        //當位置改變的時候調(diào)用
        @Override
        public void onLocationChanged(Location location) {
            //經(jīng)度
            double longitude = location.getLongitude();
            //緯度
            double latitude = location.getLatitude();

            //海拔
            double altitude = location.getAltitude();

            locationStr = longitude+"_"+latitude;
            launcher.callExternalInterface("getLocationSuccess", locationStr);
        }

        //當GPS狀態(tài)發(fā)生改變的時候調(diào)用
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

            switch (status) {

                case LocationProvider.AVAILABLE:
                    message = "當前GPS為可用狀態(tài)!";
                    break;

                case LocationProvider.OUT_OF_SERVICE:
                    message = "當前GPS不在服務(wù)內(nèi)!";
                    break;

                case LocationProvider.TEMPORARILY_UNAVAILABLE:
                    message = "當前GPS為暫停服務(wù)狀態(tài)!";
                    break;

            }
            launcher.callExternalInterface("GPSStatusChanged", message);

        }

        //GPS開啟的時候調(diào)用
        @Override
        public void onProviderEnabled(String provider) {
            message = "GPS開啟了!";
            launcher.callExternalInterface("GPSOpenSuccess", message);

        }
        //GPS關(guān)閉的時候調(diào)用
        @Override
        public void onProviderDisabled(String provider) {
            message = "GPS關(guān)閉了!";
            launcher.callExternalInterface("GPSClosed", message);

        }
    };

獲取定位:

    //獲取上次的location
    Location location = locationManager.getLastKnownLocation(provider);

    /**
     * 參1:選擇定位的方式
     * 參2:定位的間隔時間
     * 參3:當位置改變多少時進行重新定位
     * 參4:位置的回調(diào)監(jiān)聽
     */
    locationManager.requestLocationUpdates(provider, 10000, 0, locationListener);
    while(location == null){ 
        location = locationManager.getLastKnownLocation(provider); 
    } 
    //移除更新監(jiān)聽 
    locationManager.removeUpdates(locationListener);
    if (location != null) { //不為空,顯示地理位置經(jīng)緯度 
    //經(jīng)度 
    double longitude = location.getLongitude(); 
    //緯度 
    double latitude = location.getLatitude(); 
    //海拔 
    double altitude = location.getAltitude();
    locationStr = longitude+"_"+latitude; 
    launcher.callExternalInterface("getLocationSuccess", locationStr); } }

/**
* 獲取權(quán)限結(jié)果
 */
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CODE) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission Granted準許
            getLocation();
        } else {
        // Permission Denied拒絕
        }
    }
}

以下為代碼說明:
getLocation()方法實現(xiàn)定位的一系列操作洗做,但是安卓要調(diào)服務(wù)是需要驗證權(quán)限的,所以要復(fù)寫onRequestPermissionsResult方法彰居。
關(guān)鍵點:

//獲取上次的location
Location location = locationManager.getLastKnownLocation(provider);

獲取最近一次的有效location诚纸,如果沒有,則返回null陈惰。也就是說最近一次必須獲取過定位才能得到lastLocation畦徘。第一次登錄或者新安裝的app是會返回null的。

那么問題來了抬闯,如何獲取第一次的定位信息呢井辆?可以通過下面這個方法注冊請求新的位置信息:

locationManager.requestLocationUpdates(provider, 10000, 0, locationListener);

其中,provider 是使用的定位服務(wù)商溶握,主要有 網(wǎng)絡(luò)定位杯缺,GPS定位,直接取緩存:

LocationManager.NETWORK_PROVIDER睡榆, LocationManager.GPS_PROVIDER萍肆,     LocationManager.PASSIVE_PROVIDER

LocationManager本身提供了選擇最好的provider的方法:

// 獲取最好的定位方式
String provider = locationManager.getBestProvider(criteria, true); // true 代表從打開的設(shè)備中查找

但是我在上面選擇provider時做了一個檢查的操作:

// 獲取所有可用的位置提供器
List<String> providerList = locationManager.getProviders(true);
// 測試一般都在室內(nèi),這里顛倒了書上的判斷順序
if (providerList.contains(LocationManager.NETWORK_PROVIDER)) {
    provider = LocationManager.NETWORK_PROVIDER;
} else if (providerList.contains(LocationManager.PASSIVE_PROVIDER)) {
    provider = LocationManager.GPS_PROVIDER;
 } else {
    // 當沒有可用的位置提供器時胀屿,彈出Toast提示用戶
    Toast.makeText(this, "Please Open Your GPS or Location Service", Toast.LENGTH_SHORT).show();
    return;
}

原因是API本身是GPS優(yōu)先的塘揣,這樣在室內(nèi)測試時會出現(xiàn)bestprovider得到的是GPS方式,但是卻無法定位的情況(室內(nèi)GPS信號很弱宿崭,基本不可用)亲铡。所以我改成了優(yōu)先選擇網(wǎng)絡(luò)定位,然后再選擇GPS定位。實際使用時可以去掉該段操作奖蔓。
另外琅摩,locationListener是注冊的監(jiān)聽事件。其中我們要關(guān)注的是

public void onLocationChanged(Location location)

這個方法會監(jiān)聽上面的requestLocationUpdates锭硼,獲取到新的位置信息就會回調(diào)該方法,所以大家可以再這個方法里處理獲取到的location蜕劝。

不過檀头,這個定位有一個很大的問題,那就是對于部分安卓設(shè)備岖沛,第一次獲取location時暑始,會在locationManager.requestLocationUpdates處堵塞,導(dǎo)致程序一直卡在這里婴削,遲遲得不到onLocationChanged的回調(diào)廊镜。我測試了安卓5,6, 7的設(shè)備唉俗,其中兩個android5.1.1的設(shè)備一直都獲取不到location嗤朴,這就導(dǎo)致該定位無法在此設(shè)備上使用。查了各種網(wǎng)站虫溜,發(fā)現(xiàn)有兩個網(wǎng)友遇到了同樣的問題雹姊,但是取沒有解決:https://segmentfault.com/q/1010000004477439/a-1020000006144410
而且有一個奇怪的現(xiàn)象衡楞,就是我在android5.1.1的設(shè)備上測試的時候吱雏,偶爾是可以得到一次location的,但這個幾率極低瘾境。網(wǎng)上有說需要等待一段時間歧杏,但是我等了個把小時都不行。
另外我也試了google的FusedLocationProviderClient方法迷守,也是堵塞在requestLocationUpdates犬绒,實在是郁悶。由于我做的是一個海外的項目盒犹,所以什么百度API懂更,騰訊API就不用想了。
這里貼出來也是希望大神們看到之后能夠指正急膀,并希望能幫忙解決上面這個問題沮协,大家共同進步。

您的贊賞是我堅持分享的最大動力 :)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卓嫂,一起剝皮案震驚了整個濱河市慷暂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖行瑞,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奸腺,死亡現(xiàn)場離奇詭異,居然都是意外死亡血久,警方通過查閱死者的電腦和手機突照,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氧吐,“玉大人讹蘑,你說我怎么就攤上這事≈耍” “怎么了座慰?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長翠拣。 經(jīng)常有香客問我版仔,道長,這世上最難降的妖魔是什么误墓? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任蛮粮,我火速辦了婚禮,結(jié)果婚禮上谜慌,老公的妹妹穿的比我還像新娘蝉揍。我一直安慰自己,他們只是感情好畦娄,可當我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布又沾。 她就那樣靜靜地躺著,像睡著了一般熙卡。 火紅的嫁衣襯著肌膚如雪杖刷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天驳癌,我揣著相機與錄音滑燃,去河邊找鬼。 笑死颓鲜,一個胖子當著我的面吹牛表窘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甜滨,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼乐严,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衣摩?” 一聲冷哼從身側(cè)響起摧扇,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惩坑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體占婉,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年甫恩,在試婚紗的時候發(fā)現(xiàn)自己被綠了逆济。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡磺箕,死狀恐怖纹腌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滞磺,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布莱褒,位于F島的核電站击困,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏广凸。R本人自食惡果不足惜阅茶,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谅海。 院中可真熱鬧脸哀,春花似錦、人聲如沸扭吁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侥袜。三九已至蝌诡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枫吧,已是汗流浹背浦旱。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留九杂,地道東北人颁湖。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像例隆,于是被迫代替她去往敵國和親甥捺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容