Приложение падает сразу после запроса разрешения местоположения в первый раз во фрагменте - PullRequest
1 голос
/ 01 марта 2020

Я работаю в kotlin, и мой фрагмент находится внутри действия. Поэтому, когда я запускаю свое приложение и как только открывается фрагмент местоположения, оно запрашивает у меня разрешение, но сразу падает, поэтому я не могу разрешить или отклонить разрешение.

Вот мой код для фрагмент местоположения:


package com.example.atry.MakeComplaint

import android.app.Activity
import android.app.Activity.RESULT_OK
import com.example.atry.Retrofit.INodeJS
import com.example.atry.Retrofit.Observables
import com.example.atry.Retrofit.RetrofitClient
import android.content.Context
import android.content.IntentSender
import android.content.pm.PackageManager
import android.location.*
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import android.widget.Toast
import com.google.android.gms.maps.MapView

import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.atry.R
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.*
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.*
import kotlinx.android.synthetic.main.fragment_location.view.*
import retrofit2.Call
import retrofit2.Response


class LocationFragment : Fragment(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener {


    override fun onMarkerClick(p0: Marker?)= false

    private lateinit var map: GoogleMap
    private lateinit var mapView : MapView
    private lateinit var restrict:LatLngBounds

    lateinit var myAPI: INodeJS
    var MyCategory: Observables.Complainttype?=null
    private var listener: OnLocationFragmentInteractionListener? = null

    var makeComplaintobject1:Observables.final?=null

    lateinit var typename:String


    var objectComplaint =
        Observables.Complaint(
        1 , "dummy problem" ,
        "url" ,
        Observables.Location("78.4","17.4"),
        Observables.ComplaintTypes("Smell" ),
        Observables.Status( "Unresolved")

    )





    //for updating user's location/ for current location

    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private lateinit var locationRequest: LocationRequest
    private lateinit var locationCallback: LocationCallback
//    private lateinit var lastLocation: Location
    var lastLocation:Location?=null
    private var locationUpdateState = false






    companion object {
        private const val LOCATION_PERMISSION_REQUEST_CODE = 1

        private const val REQUEST_CHECK_SETTINGS = 2  //For updating user's location as they move

    }

    fun sendCategoryItem(category: Observables.Complainttype) {

        //receiving the category selected from Category Fragment

        this.MyCategory = category
        Log.d("here", "i am here 1")
        Log.d("here", MyCategory.toString())

    }





    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {

        }







        fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)


        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult?) {
                locationResult ?: return


                if (locationResult.locations.isNotEmpty()) {
                    // get latest location and sets it on the map
                    lastLocation = locationResult.lastLocation
                    Log.d("lastlocation", lastLocation.toString())


                    placeMarkerOnMap(LatLng(lastLocation!!.latitude, lastLocation!!.longitude))

                } } }



        getLocationUpdates()



        //INIT API

        val retrofit = RetrofitClient.instanc
        myAPI = retrofit.create(INodeJS::class.java)








    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val v = inflater.inflate(R.layout.fragment_location, container, false)


        mapView = v.findViewById(R.id.maps)

        mapView.onCreate(savedInstanceState)

        mapView.onResume()







        try {
        MapsInitializer.initialize(getActivity()!!.getApplicationContext())
    } catch (sendEx: IntentSender.SendIntentException) {
        sendEx.printStackTrace()
    }

        mapView.getMapAsync(this)




        v.backToList.setOnClickListener {
            backFragment()

        }

        v.forwardToDescription.setOnClickListener{

            //will proceed to the Category Description fragment only if the lastLocation isn't null

            getAllData()




        }

        return v
    }



    private fun setUpMap() {
        if (activity!!.checkSelfPermission(
                android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
            return
        }


    }


  private fun checkForPermissions(){
        if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED){



            requestPermissions( arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)

        }

      startLocationUpdates()

    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)


if(grantResults.size >0){

if(requestCode== LOCATION_PERMISSION_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED){

                locationUpdateState=true
                checkForPermissions()


}
}



    }

    /**
     * call this method in onCreate
     * onLocationResult call when location is changed
     */
    private fun getLocationUpdates() {

//with fusedLocationClient


//        fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
        locationRequest = LocationRequest()


        locationRequest.interval = 1000
        locationRequest.fastestInterval = 5000
        locationRequest.smallestDisplacement = 170f // 170 m = 0.1 mile
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //set according to your app function

        val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)

        val client = LocationServices.getSettingsClient(context!!)
        val task = client.checkLocationSettings(builder.build())

        //can update the map if location services on
        task.addOnSuccessListener {
            locationUpdateState=true
            checkForPermissions()
        }

        task.addOnFailureListener { e ->


            //check if the location settings is on yet
            if(e is ResolvableApiException){

                try{
                    e.startResolutionForResult(activity, REQUEST_CHECK_SETTINGS)
                }catch (sendEx : IntentSender.SendIntentException){

                }
            }
        }









    }



    //Places the marker on the map and changes its style.

    private fun placeMarkerOnMap(location: LatLng) {


        // 1
        val markerOptions = MarkerOptions().position(location)
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))

        // 2
        map.addMarker(markerOptions)
    }








    //start location updates
    private fun startLocationUpdates() {
        fusedLocationClient.requestLocationUpdates(
            locationRequest,
            locationCallback,
            null /* Looper */
        )
    }

    // stop location updates
    private fun stopLocationUpdates() {
        fusedLocationClient.removeLocationUpdates(locationCallback)
    }



    // start receiving location update when activity  visible/foreground

    override fun onResume() {
    super.onResume()
    mapView.onResume()

        checkForPermissions()

//        startLocationUpdates()

    }

    // stop receiving location update when activity not visible/foreground

    override fun onPause() {
    super.onPause()
    mapView.onPause()
        stopLocationUpdates()

    }

override fun onDestroy() {
    super.onDestroy()
    mapView.onDestroy()
}

override public fun onLowMemory() {
    super.onLowMemory()
    mapView.onLowMemory()
}

    override fun onMapReady(googleMap: GoogleMap?) {


        map = googleMap!!

        map.uiSettings?.isZoomControlsEnabled = true

        setUpMap()


        map.isMyLocationEnabled = true








fusedLocationClient.lastLocation.addOnSuccessListener { location ->

    //updating the map with user's current location

    if (location !=null){

        lastLocation = location
        val currentLatLng = LatLng(location.latitude,location.longitude)
        placeMarkerOnMap(currentLatLng)

        map.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng,12f))

    }


}




    }

    private fun backFragment() {
        val manager = (context as AppCompatActivity).supportFragmentManager
        manager.popBackStackImmediate()
    }




    fun getAllData(){
//
//        val latitude = 17.4
//        val longitude = 78.4

//        LocationUtils().getInstance(appContext)
//        LocationUtils().getLocation().observe(this, Observer {loc: Location? ->
//            location = loc!!
//            // Yay! location recived. Do location related work here
//            Log.i(TAG,"Location: ${location.latitude}  ${location.longitude}")
//
//        })

        if(lastLocation!=null){
             makeComplaintobject1 = Observables.final(
                Observables.ComplaintTypes(MyCategory!!.typeName),
//            Observables.Location(lastLocation.longitude.toString(),lastLocation.latitude.toString()) //lateinit wala
                Observables.Location(lastLocation!!.longitude.toString(),lastLocation!!.latitude.toString())
            )
        }
        else{
            makeComplaintobject1 = Observables.final(
                Observables.ComplaintTypes(MyCategory!!.typeName),
//            Observables.Location(lastLocation.longitude.toString(),lastLocation.latitude.toString()) //lateinit wala
                Observables.Location("","")
            )
        }


         typename = MyCategory!!.typeName


        val call = myAPI.checkExistingComplain(typename,makeComplaintobject1!!.finalLocation.longitude, makeComplaintobject1!!.finalLocation.latitude ) //new 

        Log.d("T", typename)
        Log.d("Lo", makeComplaintobject1!!.finalLocation.longitude)
        Log.d("La", makeComplaintobject1!!.finalLocation.latitude)




        call.enqueue(object : retrofit2.Callback<Observables.checkExistingResult> {
            override fun onFailure(call: Call<Observables.checkExistingResult>?, t: Throwable?) {

                Log.d("NO", t!!.message)


            }
            override fun onResponse(call: Call<Observables.checkExistingResult>?, response: Response<Observables.checkExistingResult>?) {
                Log.d("response popup", response!!.code().toString())

                //

                    if(response.code() == 200){

                    Log.d("YES", response.code().toString())
                    Log.d("response", response.body().toString())


                        if(response.body()!!.Complain === null){

                            //if type and location are in db but does not match
                            Log.d("null",response.body()!!.Complain.toString())

                            var item1 = makeComplaintobject1
                            Log.d("wohoooooo",makeComplaintobject1.toString())

                            listener!!.onLocationFragmentInteraction1(item1!!) // typeName and location going to category description

                        }
                        else{
                            //if location or type matched
                            objectComplaint = response.body()!!.Complain!!

                            Log.d("got the complaint",objectComplaint.toString())
                            setExistingData(objectComplaint)
                            val item = objectComplaint

                            listener!!.onLocationFragmentInteraction(item) // all complaint going to popup

                        }
                }


                    else if(response.code() == 500){
                        //if location or type is not in db

                        Log.d("response error", response.body().toString())
                        var item1 = makeComplaintobject1
                        Log.d("NOT IN DB",makeComplaintobject1.toString())

                        listener!!.onLocationFragmentInteraction1(item1!!)  // typeName and location going to category description


                    }

                else{

                        var item1 = makeComplaintobject1

                        Log.d("wohoooooo!1111",makeComplaintobject1.toString())

                        listener!!.onLocationFragmentInteraction1(item1!!)  // typeName and location going to category description
                    //descriptionFragment()
                }



            }
        })
    }


    interface OnLocationFragmentInteractionListener {

        fun onLocationFragmentInteraction(item: Observables.Complaint?) // all complaint going to popup
        fun onLocationFragmentInteraction1(item1: Observables.final)  // typeName and location going to category description

    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is OnLocationFragmentInteractionListener) {
            listener = context
        }
        else {
            throw RuntimeException("$context must implement OnLocationFragmentInteractionListener")
        }
    }




    fun setExistingData(test: Observables.Complaint) {
        objectComplaint = test
    }

}





Я уже запросил разрешение ACCESS_FINE_LOCATION в манифесте, и моя версия min sdk - 23, а targetdk - 26.

После многих попыток я Я все еще получаю следующую ошибку.

  java.lang.SecurityException: my location requires permission ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION

Пожалуйста, если кто-нибудь может мне помочь с этим, я действительно ценю это!

1 Ответ

0 голосов
/ 02 марта 2020

Если вы работаете на Marshmallow или более поздней версии, вам нужно проверить разрешение ACCESS_FINE_LOCATION, если пользователь предоставил или нет, если нет, то вы получите SecurityException, когда попытаетесь получить доступ к местоположению без согласия пользователя. поэтому, прежде чем получить доступ к местоположению, вы проверяете вот так -

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)

  {
      if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
      //  you can access LOCATION   
      } 
      else
      {
         ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 411);
      }
  }
  else
  {
    //  you can access LOCATION          
  }

Получить результат диалога разрешения,

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 411) {
        if (grantResults.length == 0 || grantResults == null) {
             // show dialog that you need access to go ahead
        } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Your code here permission granted
        } else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
             // show dialog that you need access to go ahead
        }
    }
}

Теперь перейдем к вашему коду

private fun checkForPermissions(){

    if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED){



        requestPermissions( arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)

    }

     startLocationUpdates()

   }

Сразу после

if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED)

на этом if condition конце вы звоните

startLocationUpdates() 

, поэтому после диалогового окна разрешения система вызывает этот метод и пытается получить обновления местоположения без пользователя Согласие и приложение Cra sh с SecurityException.

Ваш метод обновлений может быть, как показано ниже -

private fun checkForPermissions(){

    if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED){



        requestPermissions( arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)

    }else{

  startLocationUpdates()
}

}

Надеюсь, это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...