【從 0 開始開發(fā)一款直播 APP】15 Android 定位詳解之 LocationManager & Geocoder 實(shí)現(xiàn)直播定位

本文為菜鳥窩作者蔣志碧的連載青瀑÷滤校“從 0 開始開發(fā)一款直播 APP ”系列來聊聊時(shí)下最火的直播 APP,如何完整的實(shí)現(xiàn)一個(gè)類"騰訊直播"的商業(yè)化項(xiàng)目


現(xiàn)在Android 開發(fā)獲取用戶地理位置已經(jīng)愈發(fā)簡(jiǎn)單狱窘,各種地圖 SDK 都提供精確定位方法杜顺。不過如果需求中只是需要模糊定位到用戶的城市,系統(tǒng) API 完全可以滿足需求蘸炸,這時(shí)如果再集成一個(gè)地圖 SDK 顯得很臃腫躬络。系統(tǒng) API 進(jìn)行定位都很普遍了,只是在 Android 6.0 版本加入了危險(xiǎn)權(quán)限的動(dòng)態(tài)驗(yàn)證搭儒,只需要在原來基礎(chǔ)上判斷權(quán)限即可穷当。

Android 系統(tǒng)提供了地理位置服務(wù)相關(guān)的 API 方便開發(fā)者去獲取當(dāng)前的地理位置,在 android.loaction 包下主要有以下兩個(gè)類淹禾。

1馁菜、LocationManager:用于獲取地理位置的經(jīng)緯度信息

2、Geocoder:根據(jù)經(jīng)緯度獲取詳細(xì)信息/根據(jù)相信地址獲取經(jīng)緯度信息

接下來我們將實(shí)現(xiàn)直播中的定位功能铃岔。

代碼中涉及到 MVP實(shí)現(xiàn)定位汪疮,Android 6.0 運(yùn)行時(shí)權(quán)限驗(yàn)證,帶動(dòng)畫的自定義 switch 控件,請(qǐng)戳鏈接


【從 0 開始開發(fā)一款直播 APP】5.1 MVP 完全解析 -- 實(shí)現(xiàn)直播登錄
【從 0 開始開發(fā)一款直播 APP】13 Android 6.0 運(yùn)行時(shí)權(quán)限
【從 0 開始開發(fā)一款直播 APP】14 animation-list 逐幀動(dòng)畫自定義 Switch 控件


定位主要有以下權(quán)限:

//網(wǎng)絡(luò)權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
//模糊定位權(quán)限:一般用于網(wǎng)絡(luò)定位
<uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION"/>
//精確定位權(quán)限:一般用于gps定位
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

一智嚷、LocationManager

LocationManager 提供系統(tǒng)定位服務(wù)卖丸,這些服務(wù)允許應(yīng)用程序定期更新設(shè)備的地理位置,或者當(dāng)設(shè)備進(jìn)入給定地理位置附近時(shí)盏道,觸發(fā)應(yīng)用指定意圖稍浆。

LocationManager 不能直接實(shí)例化,需要使用如下方法

Context.getSystemService(Context.LOCATION_SERVICE)

在 LocationManager 中必須了解兩個(gè)重要知識(shí)點(diǎn):

1猜嘱、provider

2衅枫、LocationListener

1.1、provider

位置信息提供者朗伶。android系統(tǒng)一般提供三種方式獲取地理位置信息为鳄。

1、GPS_PROVIDER:通過 GPS 來獲取地理位置的經(jīng)緯度信息腕让。優(yōu)點(diǎn)(獲取地理位置信息精確度高)孤钦,缺點(diǎn)(只能在戶外使用,獲取經(jīng)緯度信息耗時(shí)纯丸,耗電)偏形。

2、NETWORK_PROVIDER:通過移動(dòng)網(wǎng)絡(luò)的基站或者 Wi-Fi 來獲取地理位置觉鼻。優(yōu)點(diǎn)(只要有網(wǎng)絡(luò)俊扭,就可以快速定位,室內(nèi)室外都可)坠陈,缺點(diǎn)(精確度不高)萨惑。

3、PASSIVE_PROVIDER:被動(dòng)接收更新地理位置信息仇矾,而不用自己請(qǐng)求地理位置信息庸蔼。該 PASSIVE_PROVIDER 返回的位置是通過其他 providers 產(chǎn)生的,你可以查詢 getProvider() 方法決定位置更新的由來贮匕,需要 ACCESS_FINE_LOCATION 權(quán)限姐仅,但是如果未啟用 GPS,則此 provider 可能只返回粗略位置匹配刻盐。

LocationManager 提供了以下幾種方法來獲得地理位置提供者掏膏。

//返回當(dāng)前設(shè)備的所有 provider
public List<String> getAllProviders();
//當(dāng) enabledOnly 為 true 時(shí),返回當(dāng)前設(shè)備可使用的 provider敦锌,enabledOnly 為發(fā)false馒疹,返回所有 provider
public List<String> getProviders(boolean enabledOnly);
//返回當(dāng)前設(shè)備最符合條件的 provider。Criteria:指定條件乙墙,enabledOnly:返回當(dāng)前設(shè)備可用的 provider
public String getBestProvider(Criteria criteria, boolean enabledOnly);
//返回符合條件的 provider颖变,Criteria:指定條件生均,enabledOnly:返回當(dāng)前設(shè)備可用的 provider
public List<String> getProviders(Criteria criteria, boolean enabledOnly);

Criteria

指示選擇 provider 的應(yīng)用程序標(biāo)準(zhǔn)的類。providers 可以根據(jù)準(zhǔn)確性悼做,功率使用情況,報(bào)告高度哗魂,速度和方位的能力以及貨幣成本進(jìn)行選擇肛走。該類用于指定率先選擇最符合條件的 provider,根據(jù) Cirteria 指定的條件录别,設(shè)備會(huì)自動(dòng)選擇哪種 provider朽色。

//指示緯度和經(jīng)度所需的精度。參數(shù):Criteria.ACCURACY_FINE:表示高精確度组题。Criteria.ACCURACY_COARSE:表示模糊精確度葫男。
public void setAccuracy(int accuracy);
//是否需要海拔信息
public void setAltitudeRequired(boolean altitudeRequired);
//設(shè)置方位精度。參數(shù):Criteria.NO_REQUIREMENT 無, Criteria.ACCURACY_LOW 低, Criteria.ACCURACY_HIGH 高崔列。
public void setBearingAccuracy(int accuracy);
//指示是否要求方位信息
public void setBearingRequired(boolean bearingRequired);
//是否允許收費(fèi)
public void setCostAllowed(boolean costAllowed);
//設(shè)置水平方向精準(zhǔn)度
public void setHorizontalAccuracy(int accuracy);
//設(shè)置垂直方向精準(zhǔn)度
public void setVerticalAccuracy(int accuracy);
//設(shè)置電池消耗要求 參數(shù):Criteria.NO_REQUIREMENT 無, Criteria.POWER_LOW 低, Criteria.POWER_MEDIUM 中, Criteria.POWER_HIGH 高梢褐。
public void setPowerRequirement(int level);
//設(shè)置速度精度
public void setSpeedAccuracy(int accuracy);
//是否要求速度信息
public void setSpeedRequired(boolean speedRequired);
//-----------------------------split line-------------------------------------
                             Criteria 的使用
//-----------------------------split line-------------------------------------
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);//設(shè)置定位精準(zhǔn)度
criteria.setAltitudeRequired(false);//是否要求海拔
criteria.setBearingRequired(true);//是否要求方向
criteria.setCostAllowed(true);//是否要求收費(fèi)
criteria.setSpeedRequired(true);//是否要求速度
criteria.setPowerRequirement(Criteria.NO_REQUIREMENT);//設(shè)置電池耗電要求
criteria.setBearingAccuracy(Criteria.ACCURACY_HIGH);//設(shè)置方向精確度
criteria.setSpeedAccuracy(Criteria.ACCURACY_HIGH);//設(shè)置速度精確度
criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);//設(shè)置水平方向精確度
criteria.setVerticalAccuracy(Criteria.ACCURACY_HIGH);//設(shè)置垂直方向精確度
//返回滿足條件的,當(dāng)前設(shè)備可用的location provider赵讯,當(dāng)?shù)诙€(gè)參數(shù)為false時(shí)盈咳,返回當(dāng)前設(shè)備所有provider中最符合條件的那個(gè)provider(但是不一定可用)。
String mProvider  = mLocationManager.getBestProvider(criteria,true);

1.2边翼、LocationListener 位置監(jiān)聽器接口

public interface LocationListener {
    //當(dāng)坐標(biāo)改變時(shí)觸發(fā)此函數(shù)
    void onLocationChanged(Location location);
  
    //當(dāng)provider的狀態(tài)改變時(shí)鱼响,該方法被調(diào)用。狀態(tài)有三種:
    //LocationProvider#OUT_OF_SERVICE:無服務(wù)
    //LocationProvider#TEMPORARILY_UNAVAILABLE:provider不可用
    //LocationProvider#AVAILABLE:provider可用
    void onStatusChanged(String provider, int status, Bundle extras);
  
    //當(dāng)provider可用時(shí)調(diào)用组底,比如 GPS 可用時(shí)就會(huì)調(diào)用該方法丈积。
    void onProviderEnabled(String provider);
  
    //當(dāng)provider不可用時(shí)調(diào)用該方法。比如 GPS 未打開债鸡,GPS 不可用就會(huì)調(diào)用該方法江滨。
    void onProviderDisabled(String provider);
}

1.3、獲得 LocationManager 實(shí)例

protected LocationManager  locationManager;
locationManager=(LocationManager) getSystemService(Context.LOCATION_SERVICE);

1.4厌均、綁定監(jiān)聽和解綁監(jiān)聽

locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);

locationManager.removeUpdates(locationListener);

二牙寞、Geocoder

Geocoder 用于處理正向編碼和反向編碼。地理編碼是將街道地址或其他地理位置變換為(緯度莫秆,經(jīng)度)坐標(biāo)的過程间雀。逆向地理編碼是將(緯度,經(jīng)度)坐標(biāo)轉(zhuǎn)換為(部分)地址的過程镊屎。反向地理編碼位置描述中的細(xì)節(jié)數(shù)量可能會(huì)有所不同惹挟,例如可能包含最近建筑物的完整街道地址,而另一個(gè)可能只包含城市名稱和郵政編碼。Geocoder 類需要一個(gè)未包含在核心 android 框架中的后端服務(wù)绰寞。如果平臺(tái)中沒有后端服務(wù),Geocoder 查詢方法將返回一個(gè)空列表麸恍。使用 isPresent() 方法來確定Geocoder 實(shí)現(xiàn)是否存在运怖。由于國(guó)內(nèi)使用不了Google Services 服務(wù)拼弃,因此一般的手機(jī)廠商都會(huì)在自己的手機(jī)內(nèi)內(nèi)置百度地圖服務(wù),或者高德地圖服務(wù)來替代 Google Services 服務(wù)摇展。

主要有以下方法

isPresent():判斷當(dāng)前設(shè)備是否內(nèi)置了地理位置服務(wù)吻氧。返回 true 表示 Geocoder 地理編碼可以使用,否則不可使用咏连。

getFromLocationName():返回描述地理位置信息的集合盯孙。locationName:地址,maxResults:返回地址數(shù)目(1-5)

getFromLocation():根據(jù)經(jīng)緯度返回對(duì)應(yīng)的地理位置信息祟滴。latitude:緯度振惰,longitude:經(jīng)度,maxResults:返回地址的數(shù)目(1-5)垄懂。

Geocoder 代碼示例

private static String getAddressFromLocation(final Activity activity, Location location) {
    //Geocoder初始化
    Geocoder geocoder = new Geocoder(activity);
    //判斷Geocoder地理編碼是否可用
    boolean falg = geocoder.isPresent();
    try {
        //獲取緯度和經(jīng)度
        double latitude = location.getLatitude();
        double longitude = location.getLongitude();
        //根據(jù)經(jīng)緯度獲取地理信息
        List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
        if (addresses.size() > 0) {
            //返回當(dāng)前位置骑晶,精度可調(diào)
            Address address = addresses.get(0);
            String sAddress;
            if (!TextUtils.isEmpty(address.getLocality())) {
                if (!TextUtils.isEmpty(address.getFeatureName())) {
                    //存儲(chǔ) 市 + 周邊地址
                    sAddress = address.getLocality() + " " + address.getFeatureName();
                  
                    //address.getCountryName() 國(guó)家
                    //address.getPostalCode() 郵編
                    //address.getCountryCode() 國(guó)家編碼
                    //address.getAdminArea() 省份
                    //address.getSubAdminArea() 二級(jí)省份
                    //address.getThoroughfare() 道路
                    //address.getSubLocality() 二級(jí)城市
                } else {
                    sAddress = address.getLocality();
                }
            } else {
                sAddress = "定位失敗";
            }
            return sAddress;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "";
}

三、LocationManager 使用初探

1草慧、獲取 LocationManager

2透罢、判斷定位服務(wù)(GPS,WIFI冠蒋,基站)是否可用

3羽圃、設(shè)置定位監(jiān)聽,獲取經(jīng)緯度

public void getMyLocation(Context context){
  // 獲取 LocationManager 實(shí)例
  mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
  // 判斷網(wǎng)絡(luò)定位是否可用抖剿,可替換成 GPS 定位朽寞。
  if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                    0, 0, new LocationListener() {
                @Override
                public void onLocationChanged(Location location) {
                    //位置發(fā)生改變時(shí)回調(diào)該函數(shù)
                    location.getLatitude();//緯度
                    location.getLongitude();//經(jīng)度
                }

                @Override
                public void onStatusChanged(String provider, int status, Bundle extras){
                      //狀態(tài)改變回調(diào)
                      //provider:定位器名稱(NetWork,Gps等)
                      //status: 3種狀態(tài),超出服務(wù)范圍斩郎,臨時(shí)不可用脑融,正常可用
                      //extras: 包含定位器一些細(xì)節(jié)信息
                }

                @Override
                public void onProviderEnabled(String provider) {
                    //定位開啟回調(diào)
                }

                @Override
                public void onProviderDisabled(String provider) {
                    //定位關(guān)閉回調(diào)
                }
            });
        } 
}

四缩宜、定位工具類封裝:LocationMgr

主要功能:監(jiān)測(cè)定位權(quán)限肘迎,通過網(wǎng)絡(luò)獲取位置信息,通過經(jīng)緯度解碼地理位置

public class LocationMgr {
    private static String TAG = LocationMgr.class.getSimpleName();
    private static LocationListener mLocationListener;

    //監(jiān)測(cè)定位權(quán)限
    public static boolean checkLocationPermission(final Activity activity) {
        if (Build.VERSION.SDK_INT >= 23) {
            if (PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)) {
                ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, Constants.LOCATION_PERMISSION_REQ_CODE);
                return false;
            }
        }
        return true;
    }

    /**
     * 根據(jù)經(jīng)緯度解碼地理位置
     * @param activity
     * @param location
     * @return
     */
    private static String getAddressFromLocation(final Activity activity, Location location) {
        Geocoder geocoder = new Geocoder(activity);
        try {
            double latitude = location.getLatitude();
            double longitude = location.getLongitude();
            Log.d(TAG, "getAddressFromLocation->lat:" + latitude + ", long:" + longitude);
            List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
            if (addresses.size() > 0) {
                //返回當(dāng)前位置锻煌,精度可調(diào)
                Address address = addresses.get(0);
                String sAddress;
                if (!TextUtils.isEmpty(address.getLocality())) {
                    if (!TextUtils.isEmpty(address.getFeatureName())) {
                        sAddress = address.getLocality() + " " + address.getFeatureName();
                    } else {
                        sAddress = address.getLocality();
                    }
                } else {
                    sAddress = "定位失敗";
                }
                return sAddress;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 獲取位置
     * @param activity
     * @param locationListener
     * @return
     */
    public static boolean getMyLocation(final Activity activity, final onLocationListener locationListener) {
        final LocationManager locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
      //判斷網(wǎng)絡(luò)定位是否可用
        if (!locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            //調(diào)用定位提示對(duì)話框妓布,打開定位功能
            AlertDialog.Builder builder
                    = new AlertDialog.Builder(activity);
            builder.setMessage("尚未開啟位置定位服務(wù)");
            builder.setPositiveButton("開啟", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    //啟動(dòng)定位Activity
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    activity.startActivity(intent);
                }
            });

            builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                }
            });
            
            builder.show();
            return false;
        }
        //權(quán)限檢查
        if (!checkLocationPermission(activity)) {
            return true;
        }

      // 通過網(wǎng)絡(luò)獲取位置
        Location curLoc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        if (null == curLoc) {
            mLocationListener = new LocationListener() {
                @Override
                public void onLocationChanged(Location location) {
                    //獲取解碼的地理位置
                    String strAddress = getAddressFromLocation(activity, location);
                    if (TextUtils.isEmpty(strAddress)) {
                      //定位失敗回調(diào)
                        locationListener.onLocationChanged(-1, 0, 0, strAddress);
                    } else {
                      //定位成功回調(diào)
                        locationListener.onLocationChanged(0, location.getLatitude(), location.getLongitude(), strAddress);
                    }
                  //關(guān)閉 GPS 定位功能
                    locationManager.removeUpdates(this);
                }

                @Override
                public void onStatusChanged(String provider, int status, Bundle extras) {
                  //關(guān)閉 GPS 定位功能
                    locationManager.removeUpdates(this);
                }

                @Override
                public void onProviderEnabled(String provider) {
                  //關(guān)閉 GPS 定位功能
                    locationManager.removeUpdates(this);
                }

                @Override
                public void onProviderDisabled(String provider) {
                  //關(guān)閉 GPS 定位功能
                    locationManager.removeUpdates(this);
                }
            };
          //設(shè)置監(jiān)聽器,自動(dòng)更新的最小時(shí)間為間隔N秒(1秒為1*1000宋梧,這樣寫主要為了方便)或最小位移變化超過N米
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,8000,0,mLocationListener);
        }else {
            //獲取解碼的地理位置
            String strAddress = getAddressFromLocation(activity,curLoc);
            if (TextUtils.isEmpty(strAddress)) {
              //定位失敗回調(diào)
                locationListener.onLocationChanged(-1, 0, 0, strAddress);
            } else {
              //定位成功回調(diào)
                locationListener.onLocationChanged(0, curLoc.getLatitude(), curLoc.getLongitude(), strAddress);
            }
        }
        return true;
    }
    //自定義定位監(jiān)聽回調(diào)接口
    public interface onLocationListener {
        void onLocationChanged(int code, double lat1, double long1, String location);
    }
}

五匣沼、LocationMgr 的使用

5.1、PublishPresenter :定位邏輯實(shí)現(xiàn)類

初始化 onLocationListener 定位監(jiān)聽接口捂龄,如果定位成功释涛,通過調(diào)用 mIPublishView.doLocationSuccess(location) 方法加叁,提示定位成功,mIPublishView.doLocationFailed() 提示定位失敗唇撬。定位按鈕點(diǎn)擊調(diào)用 doLocation() 方法最終完成位置信息展示它匕。

public class PublishPresenter extends IPublishPresenter {
    private IPublishView mIPublishView;
    private String TAG = PublishPresenter.class.getSimpleName();

    public PublishPresenter(IPublishView iPublishView) {
        super(iPublishView);
        this.mIPublishView = iPublishView;
    }

  public LocationMgr.onLocationListener getOnLocationListener() {
      return mOnLocationListener;
  }
    //初始化定位監(jiān)聽回調(diào)接口
  private LocationMgr.onLocationListener mOnLocationListener = new LocationMgr.onLocationListener() {
      @Override
      public void onLocationChanged(int code, double lat1, double long1, String location) {
          //0 表示成功
          if (0 == code) {
              mIPublishView.doLocationSuccess(location);
          } else {
              mIPublishView.doLocationFailed();
          }
      }
  };
  
  //定位
  @Override
  public void doLocation() {
      if (LocationMgr.checkLocationPermission(mIPublishView.getActivity())) {
          //成功返回地理位置信息結(jié)果
          boolean success = LocationMgr.getMyLocation(mIPublishView.getActivity(), mOnLocationListener);
          if (!success) {
              mIPublishView.doLocationFailed();
          }
      }
  }
}

5.2、PublishActivity

實(shí)例化定位按鈕窖认,調(diào)用定位功能 mPublishPresenter.doLocation()豫柬,實(shí)現(xiàn)定位成功和失敗方法并作處理。

public class PublishActivity extends BaseActivity implements View.OnClickListener, IPublishView{
private TextView mTvLBS;
private PublishPresenter mPublishPresenter;
@Override
protected void setListener() {
    mBtnLBS.setOnClickListener(this);
}
@Override
public void onClick(View v) {
    switch (v.getId()) {
        //定位
        case R.id.btn_lbs:
            if (mBtnLBS.isChecked()) {
                mBtnLBS.setChecked(false, true);
                mTvLBS.setText("不顯示地理位置");
            } else {
                mBtnLBS.setChecked(true, true);
                mTvLBS.setText("正在定位中");
                //調(diào)用定位功能
                mPublishPresenter.doLocation();
            }
            break;
    }
}
//定位成功
@Override
public void doLocationSuccess(String location) {
    mTvLBS.setText(location);
}
//定位失敗
@Override
public void doLocationFailed() {
    mTvLBS.setText("定位失敗");
    mBtnLBS.setChecked(false, false);
}

    /**
     * 權(quán)限驗(yàn)證回調(diào)
     * <p>
     * 1耀态、權(quán)限通過 ActivityCompat 類的 checkSelfPermission() 方法判斷是否有所需權(quán)限轮傍。PublishPresenter.java # checkPublishPermission()
     * 2暂雹、權(quán)限請(qǐng)求是通過 ActivityCompat 類中的 requestPermissions() 方法首装,
     * 在 OnRequestPermissionsResultCallback # onRequestPermissionsResult() 方法中回調(diào)。PublishActivity.java # onRequestPermissionsResult()
     * 3杭跪、應(yīng)用程序可以提供一個(gè)額外的合理的使用權(quán)限調(diào)用 Activitycompat # shouldShowRequestPermissionRationale() 方法仙逻。
     * Android 原生系統(tǒng)中,如果第二次彈出權(quán)限申請(qǐng)的對(duì)話框涧尿,會(huì)出現(xiàn)「以后不再彈出」的提示框系奉,如果用戶勾選了,你再申請(qǐng)權(quán)限姑廉,
     * 則 shouldShowRequestPermissionRationale() 返回 true缺亮,意思是說要給用戶一個(gè)解釋,告訴用戶為什么要這個(gè)權(quán)限桥言。
     *
     * @param requestCode  請(qǐng)求碼
     * @param permissions  權(quán)限數(shù)組
     * @param grantResults 授予結(jié)果數(shù)組
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            //定位權(quán)限
            case Constants.LOCATION_PERMISSION_REQ_CODE:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //獲取地理位置失敗處理
                    if (!LocationMgr.getMyLocation(this, mPublishPresenter.getOnLocationListener())) {
                        mTvLBS.setText("定位失敗");
                        mBtnLBS.setChecked(false, false);
                    }
                }
                break;
        }
    }
}

運(yùn)行結(jié)果


詳情轉(zhuǎn)至 GitHub
參考:

https://developer.android.com/reference/android/location/LocationManager.html#GPS_PROVIDER

https://developer.android.com/reference/android/location/Geocoder.html

http://blog.csdn.net/feiduclear_up/article/details/50704127

https://my.oschina.net/JumpLong/blog/89266

擼這個(gè)項(xiàng)目的一半萌踱,你就是大神 , 戳http://mp.weixin.qq.com/s/ZagocTlDfxZpC2IjUSFhHg

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市号阿,隨后出現(xiàn)的幾起案子并鸵,更是在濱河造成了極大的恐慌,老刑警劉巖扔涧,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件园担,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡枯夜,警方通過查閱死者的電腦和手機(jī)弯汰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來湖雹,“玉大人蝙泼,你說我怎么就攤上這事∪霸妫” “怎么了汤踏?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵织鲸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我溪胶,道長(zhǎng)搂擦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任哗脖,我火速辦了婚禮瀑踢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘才避。我一直安慰自己橱夭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布桑逝。 她就那樣靜靜地躺著棘劣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪楞遏。 梳的紋絲不亂的頭發(fā)上茬暇,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音寡喝,去河邊找鬼糙俗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛预鬓,可吹牛的內(nèi)容都是我干的巧骚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼格二,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼劈彪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蟋定,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤粉臊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后驶兜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扼仲,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年抄淑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屠凶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肆资,死狀恐怖矗愧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情郑原,我是刑警寧澤唉韭,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布夜涕,位于F島的核電站,受9級(jí)特大地震影響属愤,放射性物質(zhì)發(fā)生泄漏女器。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一住诸、第九天 我趴在偏房一處隱蔽的房頂上張望驾胆。 院中可真熱鬧,春花似錦贱呐、人聲如沸丧诺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驳阎。三九已至,卻和暖如春惕艳,著一層夾襖步出監(jiān)牢的瞬間搞隐,已是汗流浹背驹愚。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工远搪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逢捺。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓谁鳍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親劫瞳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子倘潜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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