简体   繁体   中英

App crashes right after asking for location permission for the first time in frament

I am working in kotlin and my fragment lies inside an activity. So when I run my app and as soon as the location fragment opens up it asks me for the permission but immediately crashes, so I'm unable to allow or deny the permission.

Here's my code for location fragment:


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
    }

}





I have already asked for the ACCESS_FINE_LOCATION permission in the manifest and my min sdk version is 23 while targetsdk is 26.

After a lot of tries I am still getting the following error.

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

Please if anyone could help me with this I'd really appreciate it!!

If you are running on Marshmallow or greater version then you need to check permission of ACCESS_FINE_LOCATION if user has granted or not if not then you will get SecurityException when you try to access location without user consent. so before accessing location You check like this -

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          
  }

Get Result of the Permission dialog,

@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
        }
    }
}

Now coming to your code

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()

   }

Right after

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

this if condition end you are calling

startLocationUpdates() 

so that's why after permission dialog system call this method and try to get location updates without user consent and app crash with SecurityException .

Your updates method could like below -

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()
}

}

Hope this will help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM