11

Following FetchAddressIntentService implementation with IntentService (in kotlin):

class FetchAddressIntentService  //Constructor of this service
    : IntentService(INTENTTAG) {
    //Receiver where results are forwarded from this service
    protected var resultReceiver: ResultReceiver? = null

    private val TAG by lazy { this::class.java.simpleName }

    //Intent Service handler
    override fun onHandleIntent(intent: Intent?) { //Errormessages
        var errorMessage = ""
        if (intent != null) {
            resultReceiver =
                intent.getParcelableExtra(RECEIVER)
        }
        //Checks if receiver was properly registered
        if (resultReceiver == null) {
            Log.wtf(
                TAG,
                "No reciever received. There is nowhere to send the results !!"
            )
            return
        }
        //Get the location passed to this service through an extra.
        var location: Location? = null
        if (intent != null) {
            location =
                intent.getParcelableExtra(LOCATION_DATA_EXTRA)
        }
        //Make sure the location is really sent
        if (location == null) {
            errorMessage = getString(R.string.gis_error_no_location_data_provided)
            Log.wtf(TAG, errorMessage)
            deliverResultToReceiver(FAILURE_RESULT, errorMessage)
            return
        }
        //Setting locale
        val geocoder = Geocoder(this, Locale.ROOT)
        //Address found
        var addresses: List<Address>? = null
        try {
            addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1)
            Log.i(TAG,"rec: address = ${addresses[0]}")
        } catch (ioException: IOException) { //Catches network or i/o problems
            errorMessage = getString(R.string.gis_error_service_not_available)
            Log.e(TAG, errorMessage, ioException)
        } catch (illegalArgumentException: IllegalArgumentException) { //Error in latitude or longitude data
            errorMessage = getString(R.string.gis_error_invalid_lat_long_used)
            Log.e(
                TAG,
                errorMessage + ". Latitude = " + location.latitude +
                        ", Longitude = " + location.longitude,
                illegalArgumentException
            )
        }
        //Handles cases where no addresses where found
        if (addresses == null || addresses.isEmpty()) {
            if (errorMessage.isEmpty()) {
                errorMessage = getString(R.string.gis_error_no_address_found)
                Log.e(TAG, errorMessage)
            }
            deliverResultToReceiver(FAILURE_RESULT, errorMessage)
        } else {
            val address = addresses[0]
            //deliverAddressToReceiver(SUCCESS_RESULT, address)
            deliverAddressToReceiver2(SUCCESS_ADDRESS,address)
        }
    }

    private fun deliverAddressToReceiver2(
        resultCode: Int,
        address: Address
    ){
        val bundle = Bundle()
        bundle.putParcelable("address",address)
        resultReceiver?.send(resultCode,bundle)
    }

    private fun deliverResultToReceiver(resultCode: Int, message: String) {
        val bundle = Bundle()
        bundle.putString(RESULT_DATA_KEY, message)
        resultReceiver!!.send(resultCode, bundle)
    }

    companion object {
        private const val INTENTTAG = "FetchAddressIS"
    }
}

Do anyone have a suggestion how I can replace IntentService with JobIntentService in a good way ?

IntentService is deprecated in Android-R / Android-11.

I have tried following some posts on this, but no one is directing the correct path how to change the usability of the IntentService call to JobIntentService call in the way this AddressFetchIntentService is using IntentService.

RG

Roar Grønmo
  • 2,926
  • 2
  • 24
  • 37
  • 2
    Your `onHandleIntent()` function turns into an `onHandleWork()` function. That, plus your superclass change from `IntentService` to `JobIntentService`, should be the bulk of the changes needed in the class itself. You will need some changes in your code that starts the service. – CommonsWare Jun 01 '20 at 18:53
  • 3
    `JobIntentService` is deprecated, use `WorkManager`. – CoolMind Aug 09 '21 at 08:47

1 Answers1

18
class FetchAddressIntentService : JobIntentService() {

    // This method is called when service starts instead of onHandleIntent
    override fun onHandleWork(intent: Intent) {
        onHandleIntent(intent)
    }

    // remove override and make onHandleIntent private.
   private fun onHandleIntent(intent: Intent?) {}

    // convenient method for starting the service.
    companion object {
        fun enqueueWork(context: Context, intent: Intent) {
            enqueueWork(context, FetchAddressIntentService::class.java, 1, intent)
        }
    }
}

You can start the service as

    val intent = Intent(this, FetchAddressIntentService::class.java)
    FetchAddressIntentService.enqueueWork(this, intent)

Important:

You need to add permissions to manifest.

<uses-permission android:name="android.permission.WAKE_LOCK" /> // needed for pre-oreo devices

also

<service
    android:name=".FetchAddressIntentService"
    android:permission="android.permission.BIND_JOB_SERVICE" // needed for oreo and above
    android:exported="true"/>

Read more here


ADDED 2020.06.02 19:20 GMT By Roar Grønmo

I changed my code to:

class FetchAddressJobIntentService:JobIntentService()
{
    private val TAG by lazy { this::class.java.simpleName }

    protected var resultReceiver: ResultReceiver? = null

    /*
    override fun onHandleWork(intent: Intent) {
        onHandleIntent(intent)
    }*/

    override fun onHandleWork(intent: Intent) { //Errormessages
        var errorMessage = ""

        resultReceiver = intent.getParcelableExtra(RECEIVER)

        //Checks if receiver was properly registered
        if (resultReceiver == null) {
            Log.wtf(
                TAG,
                "No reciever received. There is nowhere to send the results !!"
            )
            return
        }
        //Get the location passed to this service through an extra.
        var location: Location? = null

        location = intent.getParcelableExtra(LOCATION_DATA_EXTRA)

        //Make sure the location is really sent
        if (location == null) {
            errorMessage = getString(R.string.gis_error_no_location_data_provided)
            Log.wtf(TAG, errorMessage)
            deliverResultToReceiver(FAILURE_RESULT, errorMessage)
            return
        }
        //Setting locale
        val geocoder = Geocoder(this, Locale.ROOT)
        //Address found
        var addresses: List<Address>? = null
        try {
            addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1)
            Log.i(TAG,"rec: address = ${addresses[0]}")
        } catch (ioException: IOException) { //Catches network or i/o problems
            errorMessage = getString(R.string.gis_error_service_not_available)
            Log.e(TAG, errorMessage, ioException)
        } catch (illegalArgumentException: IllegalArgumentException) { //Error in latitude or longitude data
            errorMessage = getString(R.string.gis_error_invalid_lat_long_used)
            Log.e(
                TAG,
                errorMessage + ". Latitude = " + location.latitude +
                        ", Longitude = " + location.longitude,
                illegalArgumentException
            )
        }
        //Handles cases where no addresses where found
        if (addresses == null || addresses.isEmpty()) {
            if (errorMessage.isEmpty()) {
                errorMessage = getString(R.string.gis_error_no_address_found)
                Log.e(TAG, errorMessage)
            }
            deliverResultToReceiver(FAILURE_RESULT, errorMessage)
        } else {
            val address = addresses[0]
            //deliverAddressToReceiver(SUCCESS_RESULT, address)
            deliverAddressToReceiver2(SUCCESS_ADDRESS,address)
        }
    }

    private fun deliverAddressToReceiver2(
        resultCode: Int,
        address: Address
    ){
        val bundle = Bundle()
        bundle.putParcelable("address",address)
        resultReceiver?.send(resultCode,bundle)
    }

    private fun deliverResultToReceiver(resultCode: Int, message: String) {
        val bundle = Bundle()
        bundle.putString(RESULT_DATA_KEY, message)
        resultReceiver!!.send(resultCode, bundle)
    }



    companion object{
        fun enqueueWork(context: Context, intent: Intent){
            enqueueWork(context,FetchAddressJobIntentService::class.java, 1, intent)
        }
    }

}

Roar Grønmo
  • 2,926
  • 2
  • 24
  • 37
Atiq
  • 14,435
  • 6
  • 54
  • 69
  • Thanx, Max, this made it a little more clearer. I couldn't figure out how to grab the enqueueWork, but got salvaged by your 'companion object' (which I should of course figured out my self !!, but I didn't...). What actually scares me, it is conciderately faster than the original one. – Roar Grønmo Jun 02 '20 at 19:08
  • And it is like that, when examples are in Java, and we are in Kotlin... – Roar Grønmo Jun 02 '20 at 19:17
  • 1
    What if I want to perform the operation right away, even using foreground service if needed, one operation after another, in a queue? IntentService is deprecated. Isn't there any other solution? – android developer Feb 02 '21 at 19:57
  • 10
    Great answer, although the `JobIntentService` is deprecated now too – Andritchi Alexei Jul 23 '21 at 08:42
  • @Max I used a JobIntentService to fire Notifications to the user when exact Alarms were triggered. What do you suggest I use now that JobIntentService is deprecated? WorkManager? – AJW Oct 17 '21 at 19:28