Wrap location API in coroutines











up vote
1
down vote

favorite












In my app I need to query location and scan wifi periodically. To conserve power I need to change the rate dynamically, depending on the distance to the target. Also I want to wait for both asynchronous calls to complete. Coroutines seemed the obvious choice, but since this is my first take at coroutines I want to have a second opinion.



I came up with the following solution:



@SuppressLint("MissingPermission")
suspend fun getCurrentLocation(context: Context): Location? = suspendCoroutine { cont ->
val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
val locationRequest = LocationRequest()
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locationRequest.numUpdates = 1
val listener = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
cont.resume(locationResult?.lastLocation)
}
}
val task = fusedLocationProviderClient.requestLocationUpdates(locationRequest,
listener,
null)
task.addOnFailureListener { cont.resumeWithException(it) }
}


also



class WifiScanner(val context: ContextWrapper) {
val wifiManager: WifiManager

init {
wifiManager = context.baseContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
}

suspend fun getCurrentScanResult(): List<ScanResult> =
suspendCoroutine { cont ->
val wifiScanReceiver = object : BroadcastReceiver() {
override fun onReceive(c: Context, intent: Intent) {
if (intent.action?.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) == true) {
val scanResults = wifiManager.scanResults
//sort so that strongest signal is on top
scanResults.sortByDescending { it.level }
Log.i("received wifi", scanResults.toString())
context.unregisterReceiver(this)
cont.resume(scanResults)
}
}
}
context.registerReceiver(wifiScanReceiver,
IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
wifiManager.startScan()
}
}


Both are executed concurrently like this:



val location = async { getCurrentLocation() }
val wifi = async { wifiScanner.getCurrentScanResult() }
val currentLocation = location.await()
val currentWifiInfo = wifi.await()


In a quick test it works fine, but it feels like abusing the system. Can I use this like that without breaking the common conventions?










share|improve this question




























    up vote
    1
    down vote

    favorite












    In my app I need to query location and scan wifi periodically. To conserve power I need to change the rate dynamically, depending on the distance to the target. Also I want to wait for both asynchronous calls to complete. Coroutines seemed the obvious choice, but since this is my first take at coroutines I want to have a second opinion.



    I came up with the following solution:



    @SuppressLint("MissingPermission")
    suspend fun getCurrentLocation(context: Context): Location? = suspendCoroutine { cont ->
    val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
    val locationRequest = LocationRequest()
    locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
    locationRequest.numUpdates = 1
    val listener = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult?) {
    cont.resume(locationResult?.lastLocation)
    }
    }
    val task = fusedLocationProviderClient.requestLocationUpdates(locationRequest,
    listener,
    null)
    task.addOnFailureListener { cont.resumeWithException(it) }
    }


    also



    class WifiScanner(val context: ContextWrapper) {
    val wifiManager: WifiManager

    init {
    wifiManager = context.baseContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
    }

    suspend fun getCurrentScanResult(): List<ScanResult> =
    suspendCoroutine { cont ->
    val wifiScanReceiver = object : BroadcastReceiver() {
    override fun onReceive(c: Context, intent: Intent) {
    if (intent.action?.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) == true) {
    val scanResults = wifiManager.scanResults
    //sort so that strongest signal is on top
    scanResults.sortByDescending { it.level }
    Log.i("received wifi", scanResults.toString())
    context.unregisterReceiver(this)
    cont.resume(scanResults)
    }
    }
    }
    context.registerReceiver(wifiScanReceiver,
    IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
    wifiManager.startScan()
    }
    }


    Both are executed concurrently like this:



    val location = async { getCurrentLocation() }
    val wifi = async { wifiScanner.getCurrentScanResult() }
    val currentLocation = location.await()
    val currentWifiInfo = wifi.await()


    In a quick test it works fine, but it feels like abusing the system. Can I use this like that without breaking the common conventions?










    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      In my app I need to query location and scan wifi periodically. To conserve power I need to change the rate dynamically, depending on the distance to the target. Also I want to wait for both asynchronous calls to complete. Coroutines seemed the obvious choice, but since this is my first take at coroutines I want to have a second opinion.



      I came up with the following solution:



      @SuppressLint("MissingPermission")
      suspend fun getCurrentLocation(context: Context): Location? = suspendCoroutine { cont ->
      val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
      val locationRequest = LocationRequest()
      locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
      locationRequest.numUpdates = 1
      val listener = object : LocationCallback() {
      override fun onLocationResult(locationResult: LocationResult?) {
      cont.resume(locationResult?.lastLocation)
      }
      }
      val task = fusedLocationProviderClient.requestLocationUpdates(locationRequest,
      listener,
      null)
      task.addOnFailureListener { cont.resumeWithException(it) }
      }


      also



      class WifiScanner(val context: ContextWrapper) {
      val wifiManager: WifiManager

      init {
      wifiManager = context.baseContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
      }

      suspend fun getCurrentScanResult(): List<ScanResult> =
      suspendCoroutine { cont ->
      val wifiScanReceiver = object : BroadcastReceiver() {
      override fun onReceive(c: Context, intent: Intent) {
      if (intent.action?.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) == true) {
      val scanResults = wifiManager.scanResults
      //sort so that strongest signal is on top
      scanResults.sortByDescending { it.level }
      Log.i("received wifi", scanResults.toString())
      context.unregisterReceiver(this)
      cont.resume(scanResults)
      }
      }
      }
      context.registerReceiver(wifiScanReceiver,
      IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
      wifiManager.startScan()
      }
      }


      Both are executed concurrently like this:



      val location = async { getCurrentLocation() }
      val wifi = async { wifiScanner.getCurrentScanResult() }
      val currentLocation = location.await()
      val currentWifiInfo = wifi.await()


      In a quick test it works fine, but it feels like abusing the system. Can I use this like that without breaking the common conventions?










      share|improve this question















      In my app I need to query location and scan wifi periodically. To conserve power I need to change the rate dynamically, depending on the distance to the target. Also I want to wait for both asynchronous calls to complete. Coroutines seemed the obvious choice, but since this is my first take at coroutines I want to have a second opinion.



      I came up with the following solution:



      @SuppressLint("MissingPermission")
      suspend fun getCurrentLocation(context: Context): Location? = suspendCoroutine { cont ->
      val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
      val locationRequest = LocationRequest()
      locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
      locationRequest.numUpdates = 1
      val listener = object : LocationCallback() {
      override fun onLocationResult(locationResult: LocationResult?) {
      cont.resume(locationResult?.lastLocation)
      }
      }
      val task = fusedLocationProviderClient.requestLocationUpdates(locationRequest,
      listener,
      null)
      task.addOnFailureListener { cont.resumeWithException(it) }
      }


      also



      class WifiScanner(val context: ContextWrapper) {
      val wifiManager: WifiManager

      init {
      wifiManager = context.baseContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
      }

      suspend fun getCurrentScanResult(): List<ScanResult> =
      suspendCoroutine { cont ->
      val wifiScanReceiver = object : BroadcastReceiver() {
      override fun onReceive(c: Context, intent: Intent) {
      if (intent.action?.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) == true) {
      val scanResults = wifiManager.scanResults
      //sort so that strongest signal is on top
      scanResults.sortByDescending { it.level }
      Log.i("received wifi", scanResults.toString())
      context.unregisterReceiver(this)
      cont.resume(scanResults)
      }
      }
      }
      context.registerReceiver(wifiScanReceiver,
      IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
      wifiManager.startScan()
      }
      }


      Both are executed concurrently like this:



      val location = async { getCurrentLocation() }
      val wifi = async { wifiScanner.getCurrentScanResult() }
      val currentLocation = location.await()
      val currentWifiInfo = wifi.await()


      In a quick test it works fine, but it feels like abusing the system. Can I use this like that without breaking the common conventions?







      android asynchronous networking geospatial kotlin






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 at 17:03









      200_success

      127k15148411




      127k15148411










      asked Nov 18 at 21:58









      leonardkraemer

      1065




      1065



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207940%2fwrap-location-api-in-coroutines%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207940%2fwrap-location-api-in-coroutines%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Список кардиналов, возведённых папой римским Каликстом III

          Deduzione

          Mysql.sock missing - “Can't connect to local MySQL server through socket”