3

l am a beginner in Kotlin. I am using AsyncTask to execute JSON data from an API. I want to add a timeout after a certain period of time in case a user has a very slow or spotty data connection, then show the user an alert dialog, saying, "Sorry you don't have proper internet connectivity" with a button when clicked closes the app.

This is my AsyncTask code:

 inner class Arr : AsyncTask<String, String, String>(){



        }

        //        for build connection
        override fun doInBackground(vararg url: String?): String{

            var text : String
            val connection = URL(url[0]).openConnection() as HttpURLConnection

            try {
                connection.connect()
                text = connection.inputStream.use { it.reader().use{reader -> reader.readText()} }


            } finally{

                connection.disconnect()

            }
            return text
        }

        override fun onPostExecute(result: String?) {

            super.onPostExecute(result)
            handleJson(result)


        }

        override fun onProgressUpdate(vararg text: String?) {


        }
Ryan Godlonton-Shaw
  • 584
  • 1
  • 5
  • 18
Ali Ghassan
  • 1,280
  • 1
  • 22
  • 59

1 Answers1

2

There are multiple ways to achieve this thing. Two examples are as below :

  1. Adding timeout using HttpURLConnection:

    try {
        connection.connectTimeout = 5000 // We all timeout here
        connection.connect()
        text = connection.inputStream.use { it.reader().use{reader -> reader.readText()} }
    } finally{
        connection.disconnect()
    }
    
  2. Disconnecting manually using Handler & Runnable (We can achieve same thing using CountDownTimer or any other stuff too) :

    try {
        connection.connect()
        text = connection.inputStream.use { it.reader().use{reader -> reader.readText()} }
        // We all timeout here using Handler
        Handler().postDelayed(
            {
                connection.disconnect() // We disconnect manually
            },
            5000 // Timeout value
        )
    } finally{
        connection.disconnect()
    }
    

Edit for O.P.:

Use below class for making API call and showing alert to user if connection is timed out.

//We pass context to Activity/Fragment to display alert dialog
inner class TestApiCall(private val context: Context?) : AsyncTask<String, String, String?>() {

    //        for build connection
    override fun doInBackground(vararg url: String?): String? {
        var text: String? = null
        val connection = URL(url[0]).openConnection() as HttpURLConnection

        try {
            connection.connect()
            text = connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
            handleTimeout { timedOut ->
                if (timedOut) {
                    text = null
                    connection.disconnect()
                    print("Timeout Executed")
                }
            }
        } finally {
            connection.disconnect()
        }
        return text
    }

    private fun handleTimeout(delay: Long = 5000, timeout: (Boolean) -> Unit) {
        Handler(Looper.getMainLooper()).postDelayed({
            timeout(true)
        }, delay)
    }

    override fun onPostExecute(result: String?) {
        super.onPostExecute(result)
        if (result != null) {
            //Handle result here
            print("Result --> $result")
        } else {
            //Result is null meaning it can be timed out
            context?.let { ctx ->
                val alertDialog = AlertDialog.Builder(ctx)
                alertDialog.setTitle("Some title here")
                alertDialog.setMessage("Notifying user about API error")
                alertDialog.create().show()
            }
        }
    }

    override fun onProgressUpdate(vararg text: String?) {
        //Update progress from here
    }
}

Call it from Activity/Fragment by passing context and "your API URL" :

TestApiCall(context).execute("https://jsonplaceholder.typicode.com/todos/1")
Jeel Vankhede
  • 11,592
  • 2
  • 28
  • 58
  • where should l put those code ? in `onPreExecute` ? and what about alertdialog to inform user ? – Ali Ghassan Mar 30 '19 at 07:18
  • Both of solutions are related to `doInBackground()`. You can display alert to user inside `onPostExecute` method conditionally. – Jeel Vankhede Mar 30 '19 at 07:33
  • he dosent work with alertdialog . When l tried to puted alert dialog in onPostExecute method conditionally l get error Type mismatch. `Required: Boolean Found: String?` ! could you please to rewrite answer with alertdialog ? – Ali Ghassan Mar 30 '19 at 08:22