Search code examples
androidhttpurlconnectionkotlin

Android with Kotlin - How to use HttpUrlConnection


I´m trying to get data from a url inside an AsyncTask but I get an error when creating a new instance of HttpUrlConnection.

Something like this on Java

URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
    InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    readStream(in);
finally {
    urlConnection.disconnect();
}

But I keep getting the error shown below.

class GetWeatherTask : AsyncTast<Void, Void, Void>() {

    override fun doInBackground(vararg params: Void?): Void? {
        val httpClient = HttpURLConnection();
        return null
    }
    override fun onPreExecute() {
        super.onPreExecute()
    }
    override fun onPostExecute(result: Void?) {
        super.onPostExecute(result)
    }
}

Cannot access '': it is 'protected/protected and package/' in 'HttpURLConnection' Cannot create an instance of an abstract class

Am I missing something? I tryied to create a class object extending HttpUrlConnection and try to implement the init method but I couldn't

Thanks in advance.


Solution

  • Here is a simplification of the question and answer.

    Why does this fail?

    val connection = HttpURLConnection()
    val data = connection.inputStream.bufferedReader().readText()
    // ... do something with "data"
    

    with error:

    Kotlin: Cannot access '': it is 'protected/protected and package/' in 'HttpURLConnection'

    This fails because you are constructing a class that is not intended to directly be constructed. It is meant to be created by a factory, which is in the URL class openConnection() method. This is also not a direct port of the sample Java code in the original question.

    The most idiomatic way in Kotlin to open this connection and read the contents as a string would be:

    val connection = URL("http://www.android.com/").openConnection() as HttpURLConnection
    val data = connection.inputStream.bufferedReader().readText()
    

    This form will auto close everything when done reading the text or on an exception. If you want to do custom reading:

    val connection = URL("http://www.android.com/").openConnection() as HttpURLConnection
    connection.inputStream.bufferedReader().use { reader ->
        // ... do something with the reader
    }
    

    NOTE: the use() extension function will open and close the reader and handle closing on errors automatically.

    About the disconnect() method

    The docs for disconnect say:

    Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances. Calling the close() methods on the InputStream or OutputStream of an HttpURLConnection after a request may free network resources associated with this instance but has no effect on any shared persistent connection. Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.

    So you decide if you want to call it or not. Here is a version of the code that calls disconnect:

    val connection = URL("http://www.android.com/").openConnection() as HttpURLConnection
    try {
        val data = connection.inputStream.bufferedReader().use { it.readText() }
        // ... do something with "data"
    } finally {
        connection.disconnect()
    }