user5698593
user5698593

Reputation:

AsyncTask without leaks

This AsyncTask class should be static or leaks might occur

Why my AsyncTask don't work?

Call: PlacesTask(this).execute(...)

Code:

private class PlacesTask internal constructor(activity: MainActivity) : AsyncTask<String, Int, String>() {
        var data: String? = null
        private val mRef: WeakReference<MainActivity> = WeakReference(activity)

        override fun doInBackground(vararg url: String): String? {
            try {
                data = MainActivity().downloadUrl(url[0])
            } catch (e: Exception) {
                Log.d("Background Task", e.toString())
            }
            return data
        }

        override fun onPostExecute(result: String) {
            val asyncTaskLeak = mRef.get()
            if (asyncTaskLeak != null) SetPlaceTask().execute(result)
        }
    }

    private class SetPlaceTask : AsyncTask<String, Int, List<HashMap<String, String>>>() {
        var places: List<HashMap<String, String>>? = null

        override fun doInBackground(vararg jsonData: String): List<HashMap<String, String>>? {
            try {
                places = PlaceJSONParser().parse(JSONObject(jsonData[0]))
            } catch (e: Exception) {
                Log.d("Exception", e.toString())
            }
            return places
        }

        override fun onPostExecute(list: List<HashMap<String, String>>) {
           ...
        }
    }

@Throws(IOException::class)
    private fun downloadUrl(strUrl: String): String {
        var data = ""
        var iStream: InputStream? = null
        var urlConnection: HttpURLConnection? = null
        try {
            urlConnection = URL(strUrl).openConnection() as HttpURLConnection
            urlConnection.connect()
            iStream = urlConnection.inputStream
            val br = BufferedReader(InputStreamReader(iStream!!))
            val sb = StringBuilder()
            var line: String? = null
            while ({line = br.readLine(); line }() != null) sb.append(line)
            data = sb.toString()
            br.close()
        } catch (e: Exception) {
            Log.d("downloading url", e.toString())
        } finally {
            if (iStream != null) iStream.close()
            if (urlConnection != null) urlConnection.disconnect()
        }
        return data
    }

Error: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter result

Please help. What am I missing?

Upvotes: 0

Views: 898

Answers (2)

user5698593
user5698593

Reputation:

I understood.

  1. AsyncTask should be static
  2. AsyncTask move to -> companion object {}.
  3. WeakReference - For AsyncTask without leak (Good exp.)

Example: AsyncTask without leak

override fun onPause() {
        super.onPause()
        ...
        when {
            placesTask != null -> {
                placesTask!!.cancel(true)
                placesTask = null
            }
            setPlacesTask != null -> {
                setPlacesTask!!.cancel(true)
                setPlacesTask = null
            }
        }
}
    ...

    @Throws(IOException::class)
    private fun downloadUrl(strUrl: String): String {
        var data = ""
        var iStream: InputStream? = null
        var urlConnection: HttpURLConnection? = null
        try {
            urlConnection = URL(strUrl).openConnection() as HttpURLConnection
            urlConnection.connect()
            iStream = urlConnection.inputStream
            val br = BufferedReader(InputStreamReader(iStream!!))
            val sb = StringBuilder()
            var line: String? = null
            while ({line = br.readLine(); line }() != null) sb.append(line)
            data = sb.toString()
            br.close()
        } catch (e: Exception) {
            Log.d("downloading url", e.toString())
        } finally {
            if (iStream != null) iStream.close()
            if (urlConnection != null) urlConnection.disconnect()
        }
        return data
    }

companion object {
    ...
    var placesTask: PlacesTask? = null
    var setPlacesTask: SetPlaceTask? = null

    class PlacesTask(mainActivity: MainActivity) : AsyncTask<String, Int, String>() {
            private val mRef: WeakReference<MainActivity> = WeakReference(mainActivity)

            override fun doInBackground(vararg url: String): String? {
                var data: String? = null
                try {
                    data =  mRef.get()?.downloadUrl(url[0])
                } catch (e: Exception) {
                    Log.d("Background Task", e.toString())
                }
                return data
            }

            override fun onPostExecute(result: String) {
                setPlacesTask = SetPlaceTask(mRef.get()!!).execute(result) as SetPlaceTask?
            }
        }

        class SetPlaceTask(mainActivity: MainActivity) : AsyncTask<String, Int, List<HashMap<String, String>>>() {
            private val mRef: WeakReference<MainActivity> = WeakReference(mainActivity)

            override fun doInBackground(vararg jsonData: String): List<HashMap<String, String>>? {
                var places: List<HashMap<String, String>>? = null
                try {
                    places = PlaceJSONParser().parse(JSONObject(jsonData[0]))
                } catch (e: Exception) {
                    Log.d("Exception", e.toString())
                }
                return places
            }

            override fun onPostExecute(list: List<HashMap<String, String>>) {
                for (i in list.indices) {
                    val hmPlace = list[i]
                    mRef.get()?.parkingLatLng = LatLng(hmPlace["lat"]!!.toDouble(), hmPlace["lng"]!!.toDouble())
                    mRef.get()?.mMarkerPlaceLink!!.put(mRef.get()?.map!!.addMarker(MarkerOptions().icon(mRef.get()?.vectorToBitmap(R.drawable.ic_local_parking_black_12dp, ContextCompat.getColor(mRef.get()?.applicationContext, R.color.colorPrimaryDark))).position(mRef.get()?.parkingLatLng!!).title(hmPlace["place_name"] + "\n" + hmPlace["vicinity"])).id, hmPlace["reference"].toString())
                    mRef.get()?.map!!.addCircle(CircleOptions().center(mRef.get()?.parkingLatLng).radius(1.0).strokeColor(Color.BLACK).fillColor(Color.WHITE).strokeWidth(1f).zIndex(1f))
                }
            }
        }
}

Call: placesTask = PlacesTask(this).execute("https://maps.googleapis.com/maps/api/place/nearbysearch/json?location="...) as PlacesTask?

Good luck!

Upvotes: 0

Kiskae
Kiskae

Reputation: 25573

As the exception says, the parameter result is null while you've defined it as non-nullable.

Since that parameter is the value returned by doInBackground, it happens because downloadUrl threw an exception, leaving the data variable as null.

To fix it, do either of these options:

  1. Define a non-null default return value when an exception occurs, making sure that doInBackground never returns a null.
  2. Change the parameter type of onPostExecute to String? and handle the case where it might be null when an exception happens.

Upvotes: 1

Related Questions