Kotlin implements Android network request

1HttpURLConnection implementation scheme

When making a network request, the user needs to determine the permission of the request, and add the permission of the network request to the xml

 <uses-permission android:name="android.permission.INTERNET"/>

Simple implementation of network requests

class HttpURLConnectionTest:AppCompatActivity() {<!-- -->
    override fun onCreate(savedInstanceState: Bundle?) {<!-- -->
        super.onCreate(savedInstanceState)
        setContentView(R.layout.internet_layout)
        //The first way to request the network HttpURLConnection
        get_date_by_url.setOnClickListener(){<!-- -->
            sendRequestWithHttpUrl()
        }

    }
    private fun sendRequestWithHttpUrl(){<!-- -->
        thread{<!-- -->
            var connection:HttpURLConnection?=null
            try{<!-- -->
                val response = StringBuilder()
                val url= URL("https://www.baidu.com")
                connection=url. openConnection() as HttpURLConnection
                connection.connectTimeout=8000
                connection.readTimeout=8000
                //Specify the request method
               // connection.requestMethod="Post"
                //Network output, with parameter request
                //val output=DataOutputStream(connection. outputStream)
                //output.writeBytes("username=admin & amp;password=121231")
                //Network response input
                val input = connection. inputStream
                val reader=BufferedReader(InputStreamReader(input))
                reader.use{<!-- -->
                    reader.forEachLine {<!-- -->
                        response.append(it)
                    }
                }
                showResponse(response. toString())
            }catch (e:Exception){<!-- -->
                e. printStackTrace()
            }finally {<!-- -->
                //Disconnect
                connection?. disconnect()
            }
        }
    }
    private fun showResponse(response:String){<!-- -->
        //This method can perform asynchronous UI interface update
        runOnUiThread {<!-- -->
            response_data.text=response
        }
    }
}

2 Use OKHttp for network requests

First, you need to introduce the OkHttp dependency in the build.gradle file, and specify the version

 //Join OKhttp

    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
class HttpURLConnectionTest:AppCompatActivity() {<!-- -->
    override fun onCreate(savedInstanceState: Bundle?) {<!-- -->
        super.onCreate(savedInstanceState)
        setContentView(R.layout.internet_layout)
        get_date_by_okHttp.setOnClickListener(){<!-- -->
            sendRequestWithOkHttp()
        }

    }
  
    private fun sendRequestWithOkHttp(){<!-- -->
        thread {<!-- -->
            try {<!-- -->
                val client = OkHttpClient()
                val request = Request. Builder()
                    .url("https://www.baidu.com")
                    .build()
                val response = client.newCall(request).execute()
                val responseData = response.body?.string()
                if(responseData!=null){<!-- -->
                    showResponse(responseData)
                }
            }catch (e:Exception){<!-- -->
                e. printStackTrace()
            }

        }
    }
     private fun showResponse(response:String){<!-- -->
        //This method can perform asynchronous UI interface update
        runOnUiThread {<!-- -->
            response_data.text=response
        }
    }
}

Note that java.lang.ExceptionInInitializerError is reported if OkHttpClient is used. It may be a problem with the imported version of the OKhttp package, just download the appropriate version again.

A better way to write OKHttp in 3 actual scenarios

When there are relatively few requests, it is also possible to use OKHttp directly in the code, but if there are too many requests, it is impossible to put all the requests in the project code, so it is necessary to extract and abstract the request method into the tool class , to achieve a simpler call. And when performing sub-thread tasks, the result needs to be returned to the main thread, so it is necessary to use the callback interface for data update

Encapsulate HttpURLRequest tool class and OKHtttp tool class

A custom interface is required when using HttpURLRequest

interface HttpCallbackListener {<!-- -->
    fun onFinish(response: String)
    fun onError(e:Exception)
}

Then encapsulate the method and call the callback interface in the tool class

object HttpUtil {<!-- -->
    fun sendHttpRequest(address:String,listener:HttpCallbackListener){<!-- -->
        thread {<!-- -->
            var connection:HttpURLConnection?=null
            try{<!-- -->
                val response = StringBuilder()
                val url=URL(address)
                connection=url. openConnection() as HttpURLConnection
                connection.connectTimeout=8000
                connection.readTimeout=8000
                val input = connection. inputStream
                val reader=BufferedReader(InputStreamReader(input))
                reader.use {<!-- --> reader.forEachLine {<!-- -->
                    response.append(it)
                } }
                listener. onFinish(response. toString())
            }catch (e:Exception){<!-- -->
                e. printStackTrace()
                listener.onError(e)
            }finally {<!-- -->
                connection?. disconnect()
            }
        }
    }

    //The method of using OkHttp
    fun sendOKHttpRequest(address:String,callback:okhttp3.Callback){<!-- -->
        val client=OkHttpClient()
        val request = Request. Builder()
            .url(address)
            .build()
        //The child thread has been opened inside the enqueue
        client.newCall(request).enqueue(callback)
    }

Instructions

class HttpURLConnectionTest:AppCompatActivity() {<!-- -->
    override fun onCreate(savedInstanceState: Bundle?) {<!-- -->
        super.onCreate(savedInstanceState)
        setContentView(R.layout.internet_layout)
        //Use the tool class to write logic
        get_date_by_util_Httpurl.setOnClickListener{<!-- -->
            HttpUtil.sendHttpRequest("https://www.baidu.com", object :HttpCallbackListener{<!-- -->
                override fun onFinish(response: String) {<!-- -->
                    showResponse(response)
                }

                override fun onError(e: Exception) {<!-- -->
                    println("Exception handling here")
                }

            })
        }
        get_date_by_util_okHttp.setOnClickListener(){<!-- -->
            HttpUtil.sendOKHttpRequest("https://www.baidu.com", object:Callback{<!-- -->
                override fun onFailure(call: Call, e: IOException) {<!-- -->
                    println("If it fails, print exception handling")
                }

                override fun onResponse(call: Call, response: Response) {<!-- -->
                    val responseData = response.body?.string()
                    if (responseData != null) {<!-- -->
                        showResponse(responseData)
                    }
                }

            })
        }

    }
    
    private fun showResponse(response:String){<!-- -->
        //This method can perform asynchronous UI interface update
        runOnUiThread {<!-- -->
            response_data.text=response
        }
    }

   
}

4 more powerful Retrofit framework

Retrofit is a comprehensive framework based on OKHttp, with better data request specifications and response specifications

1 Create an entity class for the purpose of using GSON to map the returned object

class Student(val id:Int,val name:String,val className:String) {<!-- -->
}

2 Create a Service interface to handle the return of different request paths

interface StudentService {<!-- -->
    //The specific resource address under the website is specified here
    @GET("gete.json")
    fun getStudentInfo(): Call<List<Student>>
}

3 Use Retrofit and process the returned data

        use_Retrofit.setOnClickListener(){<!-- -->
            val retrofit = Retrofit. Builder()
            //It will be combined with the address in the Service to determine a unique request address
                .baseUrl("base address")
                .addConverterFactory(GsonConverterFactory.create())
                .build()
            val studentService = retrofit.create(StudentService::class.java)
            studentService.getStudentInfo().enqueue(object:retrofit2.Callback<List<Student>>{<!-- -->
                override fun onResponse(
                    call: retrofit2. Call<List<Student>>,
                    response: retrofit2.Response<List<Student>>
                ) {<!-- -->
                    val students = response. body()
                    if(students!=null){<!-- -->
                        for(student in students){<!-- -->
                            println("Output student information ${<!-- -->student.id}, etc.")
                        }
                    }
                }
                //handle the exception
                override fun onFailure(call: retrofit2.Call<List<Student>>, t: Throwable) {<!-- -->
                    t. printStackTrace()
                }

            })
        }

4 Solutions for some other request situations

interface StudentService {<!-- -->
    //The specific resource address under the website is specified here
    @GET("/user/Student/getStudent.json")
    fun getStudentInfo(): Call<List<Student>>
    / / Handle the situation with variable parameters in the path, keyword Path
    @GET("{page}/getStudent.json")
    fun getStudentInfoByPage(@Path("page") page:Int): Call<List<Student>>

    //Keyword Query with parameters in the path when processing the Get request
    @GET("/user/Student/getStudent.json")
    fun getStudentInfoByNameAndClassName(@Query("name") name:String,@Query("calssName") className:String):Call<List<Student>>
    //Delete a student according to id, if you don't care about the return value, use Call<ResponseBody> instead
    @DELETE("/user/Student/{id}")
    fun deleteById(@Path("id") id:Int):Call<ResponseBody>
    //If you want to submit data, submit directly according to the object
    @POST("user/Student")
    fun createStudent(@Body student:Student): Call<ResponseBody>

    //If you want to add request parameters to the request header, fill the data in the form of key-value pairs Static method
    @Headers("User-Agent:okHttp", "Cache-Control:max-age=0")
    @GET("address")
    fun getStudentBy(): Call<Student>
    //dynamic
    @GET("address 2")
    fun getStudentByDynamic(
        @Header("User-Agent") userAgent: String,
        @Header("Cache-Control") cache_control: String): Call<Student>

}
    
}

The creation process is too complicated when using Retrofit, so it is tooled

Processing in tool stack

object ServiceCreator {<!-- -->
    private const val BASE_URL="your own base access address"
    private val retrofit = Retrofit. Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    //Only provide one method to return the created Service instance externally
    fun <T> create(serviceClass: Class<T>):T= retrofit. create(serviceClass)
    
}

Instructions

use_Retrofit.setOnClickListener(){<!-- -->
            /*val retrofit=Retrofit. Builder()
                .baseUrl("base address")
                .addConverterFactory(GsonConverterFactory.create())
                .build()*/
            
            val studentService = ServiceCreator.create(StudentService::class.java)
            studentService.getStudentInfo().enqueue(object:retrofit2.Callback<List<Student>>{<!-- -->
                override fun onResponse(
                    call: retrofit2. Call<List<Student>>,
                    response: retrofit2.Response<List<Student>>
                ) {<!-- -->
                    val students = response. body()
                    if(students!=null){<!-- -->
                        for(student in students){<!-- -->
                            println("Output student information ${<!-- -->student.id}, etc.")
                        }
                    }
                }
                //handle the exception
                override fun onFailure(call: retrofit2.Call<List<Student>>, t: Throwable) {<!-- -->
                    t. printStackTrace()
                }

            })
        }