1. 程式人生 > >自定義工具類-----GPS、網路定位

自定義工具類-----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 -- 許可權已開啟")
        }

    }

}