自定义工具类-----GPS、网络定位

代码依旧是kotlin编写,java类似

1、在清单文件里添加权限

<!--请求网络权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2、新建工具类LocationUtils

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.util.Log

@SuppressLint("MissingPermission")
class LocationUtils private constructor(private val mContext: Context) {

    private var locationManager: LocationManager? = null
    private var locationProvider: String? = null
    private var location: Location? = null
    private val TAG = "LocationUtils -> baibai"
    private var logStr: String? = null

    /**
     * LocationListern监听器
     * 参数:地理位置提供器、监听位置变化的时间间隔、位置变化的距离间隔、LocationListener监听器
     */
    private var locationListener: LocationListener = object : LocationListener {

        /**
         * 当某个位置提供者的状态发生改变时
         */
        override fun onStatusChanged(provider: String, status: Int, arg2: Bundle) {

        }

        /**
         * 某个设备打开时
         */
        override fun onProviderEnabled(provider: String) {

        }

        /**
         * 某个设备关闭时
         */
        override fun onProviderDisabled(provider: String) {

        }

        /**
         * 手机位置发生变动
         */
        override fun onLocationChanged(location: Location) {
            location.accuracy//精确度
            Log.d(TAG, "手动位置发生变化 location ${location == null}")
            setLog("手动位置发生变化 location ${location == null}")
            setLocation(location)
        }
    }

    init {
        getLocation()
    }

    private fun getLocation() {
        //1.获取位置管理器
        locationManager = mContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        //2.获取位置提供器,GPS或是NetWork
        val providers = locationManager!!.getProviders(true)//如果是这个获得的是 [passive] 一个(返回的是有效的供应商列表)
//        val providers = locationManager!!.allProviders//得到 [passive, gps, network] 三个(返回的是所有的供应商列表)
        Log.d(TAG, providers.toString())
        setLog(providers.toString())
        locationProvider = when {
            //如果设备rom没有添加相关服务,把这个分支去掉,即选择的是GPS定位
            providers.contains(LocationManager.NETWORK_PROVIDER) -> {//如果是网络定位(基站或wifi)//baibai
                Log.d(TAG, "当前是网络定位")
                getLog("当前是网络定位")
                LocationManager.NETWORK_PROVIDER
            }

            providers.contains(LocationManager.GPS_PROVIDER) -> {//如果是GPS定位
                Log.d(TAG, "当前是GPS定位")
                setLog("当前是GPS定位")
                LocationManager.GPS_PROVIDER
            }

            providers.contains(LocationManager.PASSIVE_PROVIDER) -> {//如果是passive定位(即被动方式,是位置更新监测器)
                Log.d(TAG, "当前是passive定位")
                setLog("当前是passive定位")
                LocationManager.PASSIVE_PROVIDER
            }

            else -> {
                Log.d(TAG, "没有可用的位置提供器")
                setLog("没有可用的位置提供器")
                return
            }
        }
        // 需要检查权限,否则编译报错,想抽取成方法都不行,还是会报错。只能这样重复 code 了。
        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return
        }

        //3.获取上次的位置,一般第一次运行,此值为null
        val location = locationManager!!.getLastKnownLocation(locationProvider)
        Log.d(TAG, "工具类getLocation里的location是否为空: ${location == null}")
        setLog("工具类getLocation里的location是否为空: ${location == null}")
        if (location != null) {
            setLocation(location)
        }
        // 监视地理位置变化,第二个和第三个参数分别为更新的最短时间minTime和最短距离minDistace
        locationManager!!.requestLocationUpdates(locationProvider, 0, 0f, locationListener)
    }

    private fun setLocation(location: Location) {
        this.location = location
        val address = "纬度:" + location.latitude + ",  经度:" + location.longitude
        Log.d(TAG, address)
    }

    /**
     * 获取经纬度
     */
    fun showLocation(): Location? {
        return location
    }

    /**
     * 移除定位监听
     */
    fun removeLocationUpdatesListener() {
        // 需要检查权限,否则编译不过
        if (Build.VERSION.SDK_INT >= 23 &&
                ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return
        }
        if (locationManager != null) {
            uniqueInstance = null
            locationManager!!.removeUpdates(locationListener)
        }
        logStr = null
    }

    /**
     * 测试log
     */
    private fun setLog(log: String){
        logStr += log + "\n"
//        return logStr as String
    }

    fun getLog(): String{
        return logStr as String
    }

    /**
     * 静态
     */
    companion object {

        @SuppressLint("StaticFieldLeak")
        @Volatile
        private var uniqueInstance: LocationUtils? = null

        /**
         * 采用Double CheckLock(DCL)实现单例
         */
        fun getInstance(context: Context): LocationUtils? {
            if (uniqueInstance == null) {
                synchronized(LocationUtils::class.java) {
                    if (uniqueInstance == null) {
                        uniqueInstance = LocationUtils(context)
                    }
                }
            }
            return uniqueInstance
        }
    }

}

3、xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_location"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="定位" />

    <TextView
        android:id="@+id/tv_info"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#3f30"
        android:text="定位信息" />

    <TextView
        android:id="@+id/tv_log"
        android:layout_width="match_parent"
        android:layout_height="350px" />

    <View
        android:layout_width="match_parent"
        android:layout_height="2px"
        android:layout_margin="10px"
        android:background="#666" />

    <Button
        android:id="@+id/btn_remove"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20px"
        android:text="移除监听" />

    <Button
        android:id="@+id/btn_permission"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="检查权限" />

</LinearLayout>  

4、在activity里引用

import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.util.Log
import android.view.View
import bai.bai.bai.demo.R
import bai.bai.bai.demo.location.LocationUtils
import kotlinx.android.synthetic.main.activity_location.*
import android.widget.Toast

/**
 * 定位界面
 */
class LocationActivity : Activity(), View.OnClickListener {

    private var LOCATION_CODE = 111
    private var mLocationUtils: LocationUtils? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_location)
        initListener()
    }

    private fun initListener() {
        btn_location.setOnClickListener(this)
        btn_remove.setOnClickListener(this)
        btn_permission.setOnClickListener(this)
    }

    override fun onClick(v: View?) {
        when (v!!.id) {
            R.id.btn_location -> {//定位
                mLocationUtils = LocationUtils.getInstance(this)
                val location = mLocationUtils!!.showLocation()
                tv_log.text = mLocationUtils!!.getLog()
                if (location != null) {
                    val address = "纬度:" + location.latitude + ",  经度:" + location.longitude
                    tv_info.text = address
                } else {
                    tv_info.text = "location为空"
                }
            }

            R.id.btn_remove -> {//取消定位监听
                if (mLocationUtils != null) mLocationUtils!!.removeLocationUpdatesListener()
                tv_log.text = ""
                tv_info.text = ""
            }

            R.id.btn_permission -> {//检查权限
                checkPermission()
            }

        }
    }


    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        when (requestCode) {
            LOCATION_CODE -> {
                if (grantResults.isNotEmpty()
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED
                        && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                    // 权限被用户同意。
                    // 执形我们想要的操作
                    Log.d("baibai", "onRequestPermissionsResult === 弹窗已同意")

                } else {
                    Log.d("baibai", "onRequestPermissionsResult === 弹窗未同意")
                    // 权限被用户拒绝了。
                    //若是点击了拒绝和不再提醒
                    //关于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
                    }

                }
            }
        }
    }

    /**
     * 获取权限(如果没有开启权限,会弹出对话框,询问是否开启权限)
     */
    private fun checkPermission() {
        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, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), LOCATION_CODE)
            Log.d("baibai", "permission -- 权限未开启")
        } else {
            Log.d("baibai", "permission -- 权限已开启")
        }

    }

}

猜你喜欢

转载自blog.csdn.net/qq_36968707/article/details/83823267
今日推荐