I recently asked a question on how to get the HTML code from a Google API Script that fed me an IP Address, and received an answer that told me to use this Utility Class. (I am coding this in Kotlin)
package com.example.myapplication
import androidx.appcompat.app.AppCompatActivity
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.MalformedURLException
import java.net.URL
object ContentScrapper {
fun getHTMLData(activity: AppCompatActivity,url: String, scrapListener: ScrapListener) {
Thread(Runnable {
val google: URL?
val `in`: BufferedReader?
var input: String?
val stringBuffer = StringBuffer()
try {
google = URL(url)
`in` = BufferedReader(InputStreamReader(google.openStream()))
while (true) {
if (`in`.readLine().also { input = it } == null)
break
stringBuffer.append(input)
}
`in`.close()
activity.runOnUiThread {
scrapListener.onResponse(stringBuffer.toString())
}
} catch (e: MalformedURLException) {
e.printStackTrace()
activity.runOnUiThread {
scrapListener.onResponse(null)
}
}
}).start()
}
interface ScrapListener {
fun onResponse(html: String?)
}
}
And called it using this
ContentScrapper.getHTMLData(this, url, object : ContentScrapper.ScrapListener{
override fun onResponse(html: String?) {
if(html != null) {
editTexttest.setText(html)
} else {
editTexttest.setText("Not Found")
}
}
})
However, I was unable to find the string that was displayed on my screen. Below is the link that I am currently using to get the string. The HTML code that is returned to me doesn't seem to contain the string that the url below provides. Is there anything wrong with how I called it? Any help is appreciated. Thanks.
https://script.google.com/macros/s/AKfycbyjRIRl2ca_pnfz8XgccjDlaRPUNz6KY_WcyPZAROsy9EZkD35F/exec?command=GetLock1IPAddress
Related
I am trying to pre-cache/pre-buffer HLS videos to my app. I used CacheWriter to cache the (.mp4) file, But it was not able to cache segments of HLS video. Basically, I have only URL of the master playlist file which has media playlists of different qualities, and that each media playlist has segments (.ts).
So, I have to cache the master playlist and any one media playlist and then some segments and play the cached media to Exoplayer. how can I cache these?
I also visited https://github.com/google/ExoPlayer/issues/9337 But this does not have any example to do so.
This is how I cached .mp4 by CacheWriter
CacheWriter cacheWriter = new CacheWriter( mCacheDataSource,
dataSpec,
null,
progressListener);
cacheWriter.cache();
I am answering my own question for further users struggling on it.
We can pre-cache pre-cache HLS adaptive stream in ExoPlayer By using HlsDownloader provided by Exoplayer.
Add this Kotlin class to your project ExoPlayerModule.kt.
//SitaRam
package com.example.youtpackagename
import android.content.Context
import android.util.Log
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
import com.google.android.exoplayer2.source.hls.HlsMediaSource
import com.google.android.exoplayer2.source.hls.offline.HlsDownloader
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.upstream.FileDataSource
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor
import com.google.android.exoplayer2.upstream.cache.SimpleCache
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.util.concurrent.CancellationException
//bytes to be downloaded
private const val PRE_CACHE_AMOUNT = 2 * 1048576L
class ExoPlayerModule(context: Context) {
private var cronetDataSourceFactory = DefaultHttpDataSource.Factory()
//StaticMember is class which contains cookie in my case, you can skip cookies and use DefaultHttpDataSource.Factory().
/*val Cookie = mapOf("Cookie" to StaticMember.getCookie())
private var cronetDataSourceFactory = if (StaticMember.getCookie() != null) {
DefaultHttpDataSource.Factory().setDefaultRequestProperties(Cookie)
}else {
DefaultHttpDataSource.Factory()
}*/
private val cacheReadDataSourceFactory = FileDataSource.Factory()
private var cache = simpleCache.SimpleCache(context)
private var cacheDataSourceFactory = CacheDataSource.Factory()
.setCache(cache)
// .setCacheWriteDataSinkFactory(cacheSink)
.setCacheReadDataSourceFactory(cacheReadDataSourceFactory)
.setUpstreamDataSourceFactory(cronetDataSourceFactory)
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
fun isUriCached(uri: String, position: Long = 0): Boolean {
return cache.isCached(uri, position, PRE_CACHE_AMOUNT)
}
//updating cookies (if you are using cookies).
/* fun updateDataSourceFactory(){
val Cookie = mapOf("Cookie" to StaticMember.getCookie())
cronetDataSourceFactory = if (StaticMember.getCookie() != null) {
DefaultHttpDataSource.Factory().setDefaultRequestProperties(Cookie)
}else {
DefaultHttpDataSource.Factory()
}
cacheDataSourceFactory = CacheDataSource.Factory()
.setCache(cache)
// .setCacheWriteDataSinkFactory(cacheSink)
.setCacheReadDataSourceFactory(cacheReadDataSourceFactory)
.setUpstreamDataSourceFactory(cronetDataSourceFactory)
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
}*/
// TODO add the same for mp4. Also they might be a much better option, since they only have
// single track, so no matter what connection you have - loading can't happen twice
fun getHlsMediaSource(mediaItem: MediaItem): HlsMediaSource {
return HlsMediaSource.Factory(cacheDataSourceFactory)
.setAllowChunklessPreparation(true)
.createMediaSource(mediaItem)
}
fun releaseCache() = cache.release()
suspend fun preCacheUri(mediaItem: MediaItem) {
val downloader = HlsDownloader(mediaItem, cacheDataSourceFactory)
withContext(Dispatchers.IO) {
try {
downloader.download { _, bytesDownloaded, _ ->
if (MainActivity.nextUrl==mediaItem){
// Log.e("bytesCaching", "while: same $mediaItem same")
}else {
// Log.e("bytesCaching", "while: $mediaItem")
downloader.cancel()
}
if (bytesDownloaded >= PRE_CACHE_AMOUNT) {
// log("video precached at $percent%")
downloader.cancel()
}
}
} catch (e: Exception) {
if (e !is CancellationException) log("precache exception $e")
}
}
}
private fun log(s: String) {
TODO("Not yet implemented")
}
}
Initializing ExoPlayerModule
ExoPlayerModule PlayerModuleO = new ExoPlayerModule(MainActivity.this);
For Pre-Loading.
String previousUrl = "";
public void preLoad(String url) {
if (previousUrl.equals(url)) {
return;
}
previousUrl = url;
MediaItem mediaItem =MediaItem.fromUri(Uri.parse(url));
PlayerModuleO.preCacheUri(mediaItem, new Continuation<>() {
#NonNull
#Override
public CoroutineContext getContext() {
return EmptyCoroutineContext.INSTANCE;
}
#Override
public void resumeWith(#NonNull Object o) {
}
});
}
Playing cached or non-cached media.
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(url));
exoPlayer.setMediaSource(PlayerModuleO.getHlsMediaSource(mediaItem));
exoPlayer.prepare();
exoPlayer.play();
Releasing cache
PlayerModuleO.releaseCache();
If you are having any problems then feel free to ask.
I want to make Android App, which will run its local HTTP server. Through this server I want to load index.html to WebView. index.html is not working on its own. It is web app and has to be initialized on localhost. Also it is running other .js files inside assets folder.
To run this before I used python HTTP server and run it in browser from there.
I used Ktor library to create simple HTTP server but it shows just blank page. I don't know if I'm on right path with this solution at all.
My entire App:
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import io.ktor.application.install
import io.ktor.features.ContentNegotiation
import io.ktor.gson.gson
import io.ktor.http.content.default
import io.ktor.routing.routing
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.web_view)
initHttpServer()
initWebViewContent()
}
private fun initHttpServer(){
embeddedServer(Netty, 8080) {
install(ContentNegotiation) {
gson {}
}
routing {
default("/app/src/main/assets/index.html")
}
}.start(wait = true)
}
#SuppressLint("SetJavaScriptEnabled")
private fun initWebViewContent(){
webView.apply {
loadUrl("http://127.0.0.1:8080")
webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
return false
}
}
settings.apply {
setSupportZoom(true)
builtInZoomControls = true
displayZoomControls = false
javaScriptEnabled = true
javaScriptCanOpenWindowsAutomatically = true
}
}
}
}
Ok I dont need HTTP server - index.html can be loaded as:
webView.loadUrl("file:///android_asset/index.html")
index.html is placed inside /app/src/main/assets/ subfolder which is default asset folder for Android project.
class AssertFileContent(
private val context: Context,
private val path: String
) : OutgoingContent.ReadChannelContent() {
override val contentLength: Long?
get() {
val inputStream = context.assets.open(path)
val available = inputStream.available()
inputStream.close()
return available.toLong()
}
override fun readFrom() = context.assets.open(path).toByteReadChannel()
}
private const val pathParameterName = "static-content-path-parameter"
fun Route.assetsFiles(context: Context, path: String = "") {
get("{$pathParameterName...}") {
val relativePath =
call.parameters.getAll(pathParameterName)
?.joinToString(File.separator, prefix = path)
?: return#get
try {
val content =
AssertFileContent(context, relativePath)
call.respond(content)
} catch (e: FileNotFoundException) {
call.respond(HttpStatusCode.NotFound)
}
}
}
// Application.routing
static("/") {
assetsFiles(context, "/webapp")
}
// assets folder structure
webapp
- index.html
You are trying to serve using a file that doesn't exist. assets folder are packaged into APK and you can only access it through AssetManager. Ktor doesn't know about AssetManager and uses standard facilities to access local files.
I suggest copying all the web resources to internal storage and serve from there (filesDir is the path to the root directory):
private fun copyWebResources() {
val files = assets.list("web")
files?.forEach { path ->
val input = assets.open("web/$path")
val outFile = File(filesDir, path)
val outStream = FileOutputStream(outFile)
outStream.write(input.readBytes())
outStream.close()
input.close()
}
}
For the server, you can use the following setup:
embeddedServer(Netty, 3333) {
install(ContentNegotiation) {
gson {}
}
routing {
static("static") {
files(filesDir)
}
}
}
Here is example of assets folder structure:
web
index.html
script.js
Example URL for loadUrl is http://127.0.0.1:3333/static/index.html.
Also, there is a full sample project.
I see that the OP problem is fixed with local access but for anyone who genuinely want to have a web server on an android device to get to from other devices, this is what I ended up doing.
I read the html from asset using AssetManager and then serve that up with ktor:
routing {
get("/") {
val html = application.assets.open("index.html").bufferedReader()
.use {
it.readText()
}
call.respondText(html, ContentType.Text.Html)
}
}
private fun copyFile(context: Context,filePath: String){
val file = context.assets.open(filePath)
val outFile = File(context.filesDir, filePath)
val outStream = FileOutputStream(outFile)
file.copyTo(outStream)
outStream.close()}
private fun copyDir(context: Context,path:String){
val assets = context.assets
val asset = assets.list(path)
asset?.forEach { list ->
val listPath = "$path/$list"
//文件夹
if(!list.toString().contains(".")){
println("Dir::$listPath")
File(context.filesDir.path,listPath).mkdir()
copyDir(context,listPath)
return
}
println("File::$listPath")
copyFile(context,listPath)
}}
fun main(){
File(context.filesDir.path,"www").mkdir()
copyDir(context,path = "www")}
Before loading a website in WebView, I want to check the URL and make sure that it loads. If it does, show the WebView; if not, show another View with a message.
The idea is to check if the website can be loaded and depending on the response show either the "Website cannot be loaded" screen or show the WebView with URL loaded.
I have already checked if the connection is available, so no need to worry about that.
Need to support API 25+.
My solution below is trying to do two things:
Using AsyncTask "ping" a website and then
By passing context from MainActivity, call a function to show WebView (using WeakReference here to achieve that)
class MainActivity : AppCompatActivity() {
private var websiteURL = "https://www.google.com"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ...
webView.webViewClient = WebViewClient()
}
// I called this function after checking that there is Internet connection
private fun connectionResponseFunction(): String {
return if (isConnected) {
// *** is connected
// pass in "this" context from MainActivity
val downloadData = CheckLink(this)
downloadData.execute(websiteURL)
} else {
// *** not connected
}
}
private fun showWebView() {
webView.loadUrl(websiteURL)
}
companion object {
class CheckLink internal constructor(context: MainActivity) : AsyncTask<String, Void, String>() {
// Needed if you want to use webView or anything else from MainActivity
private val activityReference: WeakReference<MainActivity> = WeakReference(context)
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
val activity = activityReference.get()
if (activity == null || activity.isFinishing) return
if (result == "success") {
// URL loaded, show webView
activity.showWebView()
} else {
// URL didn't load
}
}
override fun doInBackground(vararg url: String?): String {
val linkLoaded = loadLink(url[0])
if (!linkLoaded) {
return "failure"
}
return "success"
}
private fun loadLink(urlPath: String?): Boolean {
try {
val url = URL(urlPath)
val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
connection.setRequestProperty("Connection", "close")
connection.connectTimeout = 3000
connection.connect()
val response = connection.responseCode
// 200 for success
return if (response == 200) {
true
} else {
false
}
} catch (e: Exception) {
// Handle exceptions
when (e) {
is MalformedURLException -> "loadLink: Invalid URL ${e.message}"
is IOException -> "loadLink: IO Exception reading data: ${e.message}"
is SecurityException -> { e.printStackTrace()
"loadLink: Security Exception. Needs permission? ${e.message}"
}
else -> "Unknown error: ${e.message}"
}
}
return false // Error
}
}
}
}
I'm quite new to Android and Kotlin, so I'm open to any suggestions to make it better.
I could not find any recent code that works for API 25+.
Another (shorter) alternative to AsyncTask would it be using Thread:
Thread {
val result = isHostAvailable(BuildConfig.BASE_URL)
runOnUiThread {
if (result) {
// do something ...
}
else showToast("no connection to server")
}
}.start()
and
fun isHostAvailable(urlPath: String): Boolean {
try {
val url = URL(urlPath)
val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
connection.setRequestProperty("Connection", "close")
connection.connectTimeout = 3000
connection.connect()
return when (connection.responseCode) {
200, 403 -> true
else -> false
}
} catch (e: Exception) {
when (e) {
is MalformedURLException -> "loadLink: Invalid URL ${e.message}"
is IOException -> "loadLink: IO Exception reading data: ${e.message}"
is SecurityException -> {
e.printStackTrace()
"loadLink: Security Exception. Needs permission? ${e.message}"
}
else -> "Unknown error: ${e.message}"
}
}
return false
}
Looks like ping doesn't work on emulators (How to Ping External IP from Java Android)...instead, try this on a real device, it'll work:
val process = Runtime.getRuntime().exec("/system/bin/ping -c 1 $SERVIDOR")
val pingResult = process .waitFor()
return pingResult == 0
By the way, the answer given by #quietbits is pretty obsolete...AsyncTask class was the way to go like 5 years ago...Since Android Studio supports kotlin, you should use coroutines!! the code line difference is huge...check this code labs for more info (https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#0)
In my phone's Storage, There is a file which is "MyFile.sql". There are 200 records at the file. What should I do is to import those 200 records into the app.
First, I just Initialize
llUpdate.setOnClickListener { UpgradeDB(txtUpdate!!).execute("", "", "") }
After that, I start a method, I don't know why It found the file and read already, But it doesn't import to the app. Is this because I write return = null So it didn't import to the app?
override fun doInBackground(vararg params: String): String? {
val filename = "MyFile.sql"
val sdcard = Environment.getExternalStorageDirectory()
val file = File(sdcard, filename)
if (!file.exists()) isCancelled
var dbHelper: MyDBHelper? = null
dbHelper?.writableDatabase.use { db ->
var intTotalLine = 0
var intLine = 1
BufferedReader(FileReader(file)).useLines { _ -> intTotalLine++ }
BufferedReader(FileReader(file)).use { r ->
r.lineSequence().forEach {
if (it.isNotEmpty()) {
db?.execSQL(it)
publishProgress(String.format("Updating %s/%s records", intLine, intTotalLine))
intLine++
}
}
}
}
return null
}
Can you guys Please Help me to check where are the mistakes? Thanks in advance.
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.
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()
}
The simplest way to do a get post request using HTTPUrlConnection is to create a common helper class that can be called from anywhere in the app to call the GET and POST request methods, without writing the same code again and again.
Below is the helper object (Singleton) class that you can use for the network call for GET and POST requests.
package com.dewari.ajay.androidnetworkcommunication.network
import org.json.JSONObject
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import javax.net.ssl.HttpsURLConnection
object RequestHandler {
const val GET : String = "GET"
const val POST : String = "POST"
#Throws(IOException::class)
fun requestPOST(r_url: String?, postDataParams: JSONObject): String? {
val url = URL(r_url)
val conn: HttpURLConnection = url.openConnection() as HttpURLConnection
conn.readTimeout = 3000
conn.connectTimeout = 3000
conn.requestMethod = POST
conn.doInput = true
conn.doOutput = true
val os: OutputStream = conn.outputStream
val writer = BufferedWriter(OutputStreamWriter(os, "UTF-8"))
writer.write(encodeParams(postDataParams))
writer.flush()
writer.close()
os.close()
val responseCode: Int = conn.responseCode // To Check for 200
if (responseCode == HttpsURLConnection.HTTP_OK) {
val `in` = BufferedReader(InputStreamReader(conn.inputStream))
val sb = StringBuffer("")
var line: String? = ""
while (`in`.readLine().also { line = it } != null) {
sb.append(line)
break
}
`in`.close()
return sb.toString()
}
return null
}
#Throws(IOException::class)
fun requestGET(url: String?): String? {
val obj = URL(url)
val con = obj.openConnection() as HttpURLConnection
con.requestMethod = GET
val responseCode = con.responseCode
println("Response Code :: $responseCode")
return if (responseCode == HttpURLConnection.HTTP_OK) { // connection ok
val `in` =
BufferedReader(InputStreamReader(con.inputStream))
var inputLine: String?
val response = StringBuffer()
while (`in`.readLine().also { inputLine = it } != null) {
response.append(inputLine)
}
`in`.close()
response.toString()
} else {
""
}
}
#Throws(IOException::class)
private fun encodeParams(params: JSONObject): String? {
val result = StringBuilder()
var first = true
val itr = params.keys()
while (itr.hasNext()) {
val key = itr.next()
val value = params[key]
if (first) first = false else result.append("&")
result.append(URLEncoder.encode(key, "UTF-8"))
result.append("=")
result.append(URLEncoder.encode(value.toString(), "UTF-8"))
}
return result.toString()
}
}
Using the above object class you can do your GET and POST requests as shown below:
//As this is network call it should be done in a separate thread
Thread(Runnable {
RequestHandler.requestGET(url)
RequestHandler.requestPOST(url, postJSONObject)
}).start()
Instead of using thread you can also use AsyncTask as followed:
class NetworkAsyncCall(private val context: Context, private val url: String, private val requestType:
String, private val postJSONObject: JSONObject = JSONObject()
) : AsyncTask<String?, String?, String?>() {
override fun doInBackground(vararg p0: String?): String? {
return when (requestType) {
RequestHandler.GET -> RequestHandler.requestGET(url)
RequestHandler.GET -> RequestHandler.requestPOST(url, postJSONObject)
else -> ""
}
}
override fun onPostExecute(s: String?) {
if (s != null) {
Toast.makeText(context, s, Toast.LENGTH_LONG).show()
}
}
}
You can create the asyncTask as a inner class of Activity or a seperate indipendent class.
Now to call the newtwork call via the AsyncTask NetworkAsyncCall in your onCreate() or any function from which you want call the api you can write:
NOTE: The mentioned url will not work so, you have to replace it with your own.
override fun onCreate(savedInstanceState: Bundle?) {
setContentView(R.layout.activity_main)
// Change the url with your own GET URL request
val urlGET = "http://my-json-feed"
//GET Request
NetworkAsyncCall(this#MainActivity, urlGET, RequestHandler.GET).execute();
// POST Request
// doPost()
}
For POST request you can call:
private fun doPost() {
// Change the url with your own POST URL request
val urlPOST = "http://my-json-feed"
val postDataParams = JSONObject()
postDataParams.put("name", "Ajay")
postDataParams.put("email", "aj****ri#gmail.com")
postDataParams.put("phone", "+91 78******25")
NetworkAsyncCall(this#MainActivity, urlPOST, RequestHandler.POST, postDataParams).execute()
}
you can check the complete code in github here.
For a good explanation you can check this link.
the advantage of using the NetworkAsyncCall as seperate indipendent class is you don't have to write the AsyncTask code again, just call the same AsyncTask NetworkAsyncCall with a new object from different activitys/functions, however with this you have to implement a listener interface that you will require for the callback on onPostExecute() after getting the response from the api and to return back the response to the activity you have to perform the callback using that interface.
You can adaptaion your code; Don't forget user Runnable thread.
Thread(Runnable {
try {
val url = URL("www.android.com")
val con = url.openConnection() as HttpURLConnection
val datas = con.inputStream.bufferedReader().readText()
val json = JSONObject(datas)
val blockList = json.getJSONObject("blockList")
val warning = json.get("warnMessage").toString()
val keys = blockList.keys()
var permission = HashMap<String, Array<String?>>()
while (keys.hasNext()) {
val key = keys.next()
val kods = blockList.getJSONArray(key)
val permissonArray = arrayOfNulls<String>(kods.length())
for (i in permissonArray.indices) {
permissonArray[i] = kods.getString(i)
}
permission[key] = permissonArray;
}
} catch (ex: Exception) {
Log.d("Exception", ex.toString())
}
}).start()