Search code examples
androidandroid-fragmentslocationhandlerui-thread

How to keep updating textview with the location accuracy from a fragment


I would like to update the users' location accuracy every 2 seconds.

I have created this function getAccuracy(activity, currentAccuracy) that updates the textView with the current location whenever it is called.

I would like it to be called every 2 seconds. This is my current code but it doesn't work - the text doesn't get a value even once and stays blank, where if I use the function without the runOnUiThread it will show at least once.

    val activity = activity as CameraActivity


    val handler = Handler()
    val delay: Long = 2000 //milliseconds

    handler.postDelayed(object : Runnable {
        override fun run() {

            activity.runOnUiThread {
                object : Runnable {
                    override fun run() {
                        getAccuracy(activity, currentAccuracy)
                    }
                }
            }

            handler.postDelayed(this, delay)
        }
    }, delay)

This is the function, using the AirLocation library

fun getAccuracy(activity: Activity, currentAccuracy: TextView) {

    airLocation = AirLocation(activity, true, true, object : AirLocation.Callbacks {
        override fun onSuccess(location: Location) {
            currentAccuracy.text = location.accuracy.toString()
            Log.d("locationAccuracy","Success")
        }

        override fun onFailed(locationFailedEnum: AirLocation.LocationFailedEnum) {
            Log.d("locationAccuracy","Fail")

        }

    })

}

Solution

  • You are re-creating the AirLocation instance every 2 seconds which is not good because it probably won't have enough time to even get location data. You should use the same instance. To fix the issue...

    You should make the airLocation variable a private member variable of the class. I think you've already done that...

    class YourActivity : AppCompatActivity() {
    
        private var airLocation: AirLocation? = null
    }
    

    Then initialize that variable in onCreate

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.main_activity)
    
            airLocation = AirLocation(this, true, true, object: AirLocation.Callbacks {
                    override fun onSuccess(location: Location) {
                        if(location != null){
                            currentAccuracy.text = location.accuracy.toString()
                        }
                    }
    
                    override fun onFailed(locationFailedEnum: AirLocation.LocationFailedEnum) {
                    }
    
                })
    }
    

    Then override the onActivityResult and call the AirLocation's onActivityResult

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            airLocation?.onActivityResult(requestCode, resultCode, data)
            super.onActivityResult(requestCode, resultCode, data)
        }
    

    That should work assuming you are handling the required permissions and location settings are on. Unfortunately this library doesn't allow you set the interval between location requests, the interval is set to 10 seconds with the fastest interval to 2 seconds, you can't change that. Here's a snippet of the source code...

    val locationRequest = LocationRequest().apply {
            interval = 10000
            fastestInterval = 2000
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
            numUpdates = 1
        }
    

    However, if it is crucial for you to be in control of the intervals, you can build your own implementation. It's not that hard. Good luck