Android开发之获取定位权限的方法
白羽 2018-07-04 来源 :网络 阅读 99 评论 0

摘要:本文将带你了解Android开发之获取定位权限的方法,希望本文对大家学Android有所帮助。


 

前言:

 

有时候我们仅仅是想要获取设备所在的经纬度,那么直接调用Android相关的api就可以了,不需要去接入高德地图或者谷歌地图等等。

 

一、获取定位服务

 

private LocationManager locationManager;
locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
 
 
二、获取所有可用的位置提供器
 
 //获取所有可用的位置提供器
  List<String> providers = locationManager.getProviders(true);
 
 
三、判断可用的位置提供器类型,是网络定位,还是GPS定位,若是都没有,那么就跳转至设置界面,提示打开网络和GPS定位服务
 
这里说一下两种定位的区别:
 
通过GPS定位,较精确,也比较耗电,而网络定位精度不高,省电。
 
复制代码
String locationProvider = null;
      if (providers.contains(LocationManager.GPS_PROVIDER)) {
    //如果是GPS
    locationProvider = LocationManager.GPS_PROVIDER;
    } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
    //如果是Network
    locationProvider = LocationManager.NETWORK_PROVIDER;
    } else {
        Intent i = new Intent();
        i.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        mContext.startActivity(i);
        return null;
    }
复制代码
 
 
四、获取Location
 
//获取Location
Location location = locationManager.getLastKnownLocation(locationProvider);
 
 
五、监视地理位置变化
 
这里设置3秒监听一次
 
//监视地理位置变化
locationManager.requestLocationUpdates(locationProvider, 3000, 1, locationListener);
 
 
六、实现地理位置变化接口
 
复制代码
public LocationListener locationListener = new LocationListener() {
 
        // Provider的状态在可用、暂时不可用和无服务三个状态直接切换时触发此函数
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
 
        }
 
        // Provider被enable时触发此函数,比如GPS被打开
        @Override
        public void onProviderEnabled(String provider) {
 
        }
 
        // Provider被disable时触发此函数,比如GPS被关闭
        @Override
        public void onProviderDisabled(String provider) {
 
        }
 
        //当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发
        @Override
        public void onLocationChanged(Location location) {
        }
    };
复制代码
 
 
注意:
 
要在文件清单里面写上
 
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
 
我为此写了个工具类。
 
复制代码
package com.example.chatting.chatting.utils;
 
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
 
 
import java.util.List;
 
/**
 * Created by Administrator on 2018/4/17.
 * 获取用户的地理位置
 */
public class GPSUtils {
 
    private static GPSUtils instance;
    private Context mContext;
    private LocationManager locationManager;
 
    private GPSUtils(Context context) {
        this.mContext = context;
    }
 
    public static GPSUtils getInstance(Context context) {
        if (instance == null) {
            instance = new GPSUtils(context);
        }
        return instance;
    }
 
    /**
     * 获取经纬度
     *
     * @return
     */
    public String getLngAndLat(OnLocationResultListener onLocationResultListener) {
        double latitude = 0.0;
        double longitude = 0.0;
 
        mOnLocationListener = onLocationResultListener;
 
        String locationProvider = null;
        locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
        //获取所有可用的位置提供器
        List<String> providers = locationManager.getProviders(true);
 
        if (providers.contains(LocationManager.GPS_PROVIDER)) {
            //如果是GPS
            locationProvider = LocationManager.GPS_PROVIDER;
        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
            //如果是Network
            locationProvider = LocationManager.NETWORK_PROVIDER;
        } else {
            Intent i = new Intent();
            i.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            mContext.startActivity(i);
            return null;
        }
 
        //获取Location
        Location location = locationManager.getLastKnownLocation(locationProvider);
        if (location != null) {
            //不为空,显示地理位置经纬度
            if (mOnLocationListener != null) {
                mOnLocationListener.onLocationResult(location);
            }
 
        }
        //监视地理位置变化
        locationManager.requestLocationUpdates(locationProvider, 3000, 1, locationListener);
        return null;
    }
 
 
    public LocationListener locationListener = new LocationListener() {
 
        // Provider的状态在可用、暂时不可用和无服务三个状态直接切换时触发此函数
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
 
        }
 
        // Provider被enable时触发此函数,比如GPS被打开
        @Override
        public void onProviderEnabled(String provider) {
 
        }
 
        // Provider被disable时触发此函数,比如GPS被关闭
        @Override
        public void onProviderDisabled(String provider) {
 
        }
 
        //当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发
        @Override
        public void onLocationChanged(Location location) {
            if (mOnLocationListener != null) {
                mOnLocationListener.OnLocationChange(location);
            }
        }
    };
 
    public void removeListener() {
        locationManager.removeUpdates(locationListener);
    }
 
    private OnLocationResultListener mOnLocationListener;
 
    public interface OnLocationResultListener {
        void onLocationResult(Location location);
 
        void OnLocationChange(Location location);
    }
}
复制代码
 
 
这里边涉及到了另一个问题,获取权限
 
对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要访问通讯录、短信等)。而在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。
 
 
 
新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。
 
 
 
对于Dangerous Permission,我们需要动态获取权限,那么我们怎么动态定位权限呢?
 
在activity中(其实我们可以把权限的获取写在一个BaseActivity中)我们可以这么做:
 
1、判断版本,如果6.0以下,那么便不需要获取权限。
 
 
 
复制代码
/**
     * 是否应该检查权限
     * @return
     */
    public boolean showCheckPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return true;
        } else {
            return false;
        }
    }
复制代码
 
 
 
 
2、若是6.0以及以上的话,那么便去判断是否已经授权,若是没有授权,那么便会去申请授权。若是已经授权,那么便直接执行我们的操作。
 
(判断之后若是没有授权,会弹出系统对话框询问是否同意授权,该对话框不可定制。)
 
复制代码
 //获取权限(如果没有开启权限,会弹出对话框,询问是否开启权限)
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            //请求权限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_CODE);
        } else {
           
        }
复制代码
 
 
 
 
3、授权回调。询问是否同意授权的时候,系统会弹出对话框,我们选择之后,会进行回调。在回调里面进行判断。
 
复制代码
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case LOCATION_CODE: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED
                        && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                    // 权限被用户同意。
                    // 执形我们想要的操作
                } else {
                    
                }
            }
        }
    }
复制代码
 
 
若是同意了,那么便可以直接执形我们的操作,若是不同意,那么下次依旧会弹出询问的对话框。不过这个对话框与之前比起来多了一个选项,那就是“不再提醒”(第一次询问没有这个选项)。这就难办了,若是点击了不再提醒,那么以后就不会再弹出对话框了,唉,那我们怎么判断呢?
 
Google给我们提供了一个方法:
 
ActivityCompat.shouldShowRequestPermissionRationale
该方法主要是为了给用户提供解释。
 
这个方法,在没弄明白之前,也是挺烦人。弄明白之后就好办了,那么,我们需要弄明白它的返回值。
 
(1)、当用户第一次被询问是否授权的时候,该方法返回值为false
 
(2)、若是用户上一次拒绝授权,但是没有点击“不再提醒“”的时候,这一次返回true。(我们可以根据这个判断,在这一次给用户一个解释,解释为什么该app需要该权限)
 
(3)、当用户上一次拒绝授权,并且点击了“不再提醒”的时候,那么返回false。
 
(4)、当用户在设置界面手动关闭了该APP的权限,那么也返回false。
 
 
 
那么,就出现了一个问题,这么多种情况都返回false,那么我们要怎么判断是哪一种情况呢?
 
比如第一与第三种情况。
 
若是我们在进行权限判断之前调用这个方法:
 
复制代码
 if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                            || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
.....
 
                    }
 
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
复制代码
若是返回true,说明是第二种情况,需要给用户一个解释(我们可以给出一个对话框,点击确定后再执形检测权限的操作,即下面的的操作)。
 
若是返回false,那么到底是第一还是第三种情况。我们无法判断。这里我给出一种方法:在授权回调里面去检测,如下。
 
else可以说明已经拒绝授权。
 
然后调用shouldShowRequestPermissionRationale方法,若是返回false,说明
 
1、点击了“不再提醒”。
 
2、该app本身没有权限,被关闭。
 
那么我们就可以提醒用户去设置界面手动开启权限。
 
复制代码
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case LOCATION_CODE: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED
                        && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                    // 权限被用户同意。
                    // 执形我们想要的操作
                } else {
                    // 权限被用户拒绝了。
                    //若是点击了拒绝和不再提醒
                    //关于shouldShowRequestPermissionRationale
                    // 1、当用户第一次被询问是否同意授权的时候,返回false
                    // 2、当之前用户被询问是否授权,点击了false,并且点击了不在询问(第一次询问不会出现“不再询问”的选项),
                    // 之后便会返回false
                    // 3、当用户被关闭了app的权限,该app不允许授权的时候,返回false
                    // 4、当用户上一次不同意授权,没有点击“不再询问”的时候,下一次返回true
                    if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                            || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
                        //提示用户前往设置界面自己打开权限
                        Toast.makeText(this, "请前往设置界面打开权限", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    
                }
            }
        }
    }


本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!


本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论
加入IT交流圈
JAVA工程师交流群 +加入
大数据架构师交流群 +加入
人工智能Python交流群 +加入
WEB/H5前端交流群 +加入
大数据岗位高薪定向就业名额  提前锁定高薪职位
移动开发直通车

  • 资料索取

  • 答疑解惑

  • 技术交流

  • 职业测评

  • 面试技巧

  • 高薪秘籍
海同名师推荐 更多>>
张军 联系TA
10年项目开发经验,精通pc、mobile平台软件开发主流技术和框架
杨成江 联系TA
青春为马 不负韶华
翟健 联系TA
熟悉系大型项目开发业务流程,精通C、Java语言
黄骈 联系TA
认证System Analyst,System Architect
程光淼 联系TA
精通C、C++等语言、智能芯片开发
热门就业培训班 更多>>
【零基础】人工智能+Python全栈开发课程
登顶技术风口浪潮巅峰 年薪百万不是梦
【零基础】JavaEE高级开发工程师课程
小白0基础入学 8000起薪轻松进名企
【零基础】大数据与分布式架构师课程
掌握大数据分布式架构 冲击年薪50W+
Android30天热搜词 更多>>
X
免费获取海同IT培训资料
验证码手机号,获得海同独家IT培训资料
获取验证码
提交

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号