1HttpURLConnection的实现方案
网络请求时需要用户确定请求的权限,在xml中加入网络请求的权限
<uses-permission android:name="android.permission.INTERNET"/>
网络请求的简单实现
class HttpURLConnectionTest:AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.internet_layout)
//第一种请求网络的方式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
//指定请求方式
// connection.requestMethod="Post"
//网络输出,附带参数请求
//val output=DataOutputStream(connection.outputStream)
//output.writeBytes("username=admin&password=121231")
//网络响应输入
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 {
//断开连接
connection?.disconnect()
}
}
}
private fun showResponse(response:String){
//此方法可以进行异步的ui界面更新
runOnUiThread {
response_data.text=response
}
}
}
2使用OKHttp进行网络请求
首先需要在build.gradle文件中引入OkHttp的依赖,指定版本
//加入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){
//此方法可以进行异步的ui界面更新
runOnUiThread {
response_data.text=response
}
}
}
注意如果使用OkHttpClient报错java.lang.ExceptionInInitializerError。可能是OKhttp包的引入版本问题,重新下载合适版本即可。
3实际场景下使用OKHttp较好的写法
在有请求且比较少的时候,直接在代码中使用OKHttp也是可以的,但是如果请求过多,不可能将请求全都放在项目代码里,所以需要对请求的方法进行一个提取抽象到工具类里面,来实现更加简单的调用。并且在进行子线程任务时,需要将结果返回到主线程,所以需要使用回调接口的方式进行数据更新
封装HttpURLRequest工具类和OKHtttp工具类
在使用HttpURLRequest时需要自定义接口
interface HttpCallbackListener {
fun onFinish(response:String)
fun onError(e:Exception)
}
然后在工具类中进行方法的封装和回调接口的调用
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()
}
}
}
//使用OkHttp的方法
fun sendOKHttpRequest(address:String,callback:okhttp3.Callback){
val client=OkHttpClient()
val request=Request.Builder()
.url(address)
.build()
//在enqueue的内部已经开启了子线程
client.newCall(request).enqueue(callback)
}
使用方法
class HttpURLConnectionTest:AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.internet_layout)
//使用工具类进行逻辑的编写
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("在这里进行异常的处理")
}
})
}
get_date_by_util_okHttp.setOnClickListener(){
HttpUtil.sendOKHttpRequest("https://www.baidu.com",object:Callback{
override fun onFailure(call: Call, e: IOException) {
println("失败的话打印异常处理")
}
override fun onResponse(call: Call, response: Response) {
val responseData=response.body?.string()
if (responseData != null) {
showResponse(responseData)
}
}
})
}
}
private fun showResponse(response:String){
//此方法可以进行异步的ui界面更新
runOnUiThread {
response_data.text=response
}
}
}
4功能更加强大的Retrofit框架
Retrofit是在OKHttp基础之上的一个综合框架,有着更好的数据请求规范和响应规范
0加入依赖库
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
1创建实体类,目的是为了使用GSON对返回对象进行映射
class Student(val id:Int,val name:String,val className:String) {
}
2创建Service接口,来处理不同请求路径的返回
interface StudentService {
//这里指定了网站下具体的资源地址
@GET("gete.json")
fun getStudentInfo(): Call<List<Student>>
}
3使用Retrofit,并处理返回数据
use_Retrofit.setOnClickListener(){
val retrofit=Retrofit.Builder()
//会和Service中的地址进行组合,来确定成为一个唯一的请求地址
.baseUrl("基础地址")
.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("输出学生的信息${
student.id}等即可")
}
}
}
//处理异常
override fun onFailure(call: retrofit2.Call<List<Student>>, t: Throwable) {
t.printStackTrace()
}
})
}
4一些其他请求情况的解决方案
interface StudentService {
//这里指定了网站下具体的资源地址
@GET("/user/Student/getStudent.json")
fun getStudentInfo(): Call<List<Student>>
//处理路径中带有可变参数的情况,关键词Path
@GET("{page}/getStudent.json")
fun getStudentInfoByPage(@Path("page") page:Int):Call<List<Student>>
//处理Get请求时路径中带有参数的情况关键词Query
@GET("/user/Student/getStudent.json")
fun getStudentInfoByNameAndClassName(@Query("name") name:String,@Query("calssName") className:String):Call<List<Student>>
//按照id删除一个学生,如果对返回值不关心,就是用Call<ResponseBody>代替
@DELETE("/user/Student/{id}")
fun deleteById(@Path("id") id:Int):Call<ResponseBody>
//如果想要提交数据,直接按照对象进行提交
@POST("user/Student")
fun createStudent(@Body student:Student):Call<ResponseBody>
//如果希望在请求头header中加入请求参数,就按照键值对的方式进行填充数据静态方式
@Headers("User-Agent:okHttp","Cache-Control:max-age=0")
@GET("地址")
fun getStudentBy():Call<Student>
//动态
@GET("地址2")
fun getStudentByDynamic(
@Header("User-Agent") userAgent:String,
@Header("Cache-Control") cache_control:String):Call<Student>
}
}
使用Retrofit时创建过程太过复杂,因此将其进行工具化的处理
在工具累中进行处理
object ServiceCreator {
private const val BASE_URL="自己的基础访问地址"
private val retrofit=Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
//只提供一个方法即可对外返回创建的Service实例
fun <T> create(serviceClass: Class<T>):T= retrofit.create(serviceClass)
}
使用方法
扫描二维码关注公众号,回复:
15522328 查看本文章
use_Retrofit.setOnClickListener(){
/*val retrofit=Retrofit.Builder()
.baseUrl("基础地址")
.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("输出学生的信息${
student.id}等即可")
}
}
}
//处理异常
override fun onFailure(call: retrofit2.Call<List<Student>>, t: Throwable) {
t.printStackTrace()
}
})
}