IntentService is deprecated, how do I replace it with JobIntentService?

25.9k views Asked by At

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

2

There are 2 answers

5
Atiq On BEST ANSWER
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)
        }
    }

}

0
user3072571 On

As for 12/12/2023: Sorry but JobIntentService deprecated. Instead we should use WorkManager Reference to document: https://developer.android.com/topic/libraries/architecture/workmanager#java and https://developer.android.com/codelabs/android-workmanager-java#3

in short:

  1. extend class from androidx.work.Worker

  2. Implement public Result doWork()

  3. Return Result.failure() or Result.success()

  4. Add dependency if needed: implementation 'com.google.guava:guava:29.0-android'

  5. Start you work:

WorkManager.getInstance(this).enqueueUniqueWork("name",
               ExistingWorkPolicy.KEEP,
               OneTimeWorkRequest.from(   ... class what extend Worker ...));

PS Hate google. They always do incompatible braking changes instead of fixing it.