Kotlin/Android中执行网络请求

方式一:使用okhttp3
okhttp官网
okhttp3 github地址

打开build.gradle.kts文件加入依赖

dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.9.0")
}

在IDEA的Gradle面板点击reload按钮便会自动下载jar

在这里插入图片描述
使用网络请求时需要把网络的权限打开,不然会提示java.lang.SecurityException: Permission denied (missing INTERNET permission?)诸如此类的报错

在这里插入图片描述
AndroidManifest.xml文件的manifest节点下添加如下代码以表示使用网络权限

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

为了方便使用可以对okhttp3进行封装一下

MainActivity.kt代码如下

package com.demo.composestudy

import android.content.ContentValues.TAG
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign

import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response

import java.io.IOException



class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            showUI()
        }

    }
}



@Composable
fun showUI(){
    var resultstring by remember { mutableStateOf("") }

    Column(){
        Button(
            onClick = {
                var url = "https://www.baidu.com";

                val client = OkHttpClient();


                // 创建一个Request对象
                var request: Request = Request.Builder()
                    .url(url)
                    .build();

                //发起call请求
                val call: Call = client.newCall(request)

                //异步请求
                call.enqueue(object : Callback {
                    override fun onFailure(call: Call, e: IOException) {
                        Log.d(TAG, "onFailure IOException:{$e}");
                    }
                    override fun onResponse(call: Call, response: Response) {
                        //接收返回响应
                        val result = response.body?.string()?:"";

                        resultstring = result;

                        Log.d(TAG, "result:{$result}");
                    }
                });

        }){
        Text("点击进行请求")
    }

    Text(
        "$resultstring",
        Modifier.fillMaxWidth(),
        textAlign = TextAlign.Center,
        style = MaterialTheme.typography.titleMedium
    )

}

}

这里需要使用异步请求,使用同步请求会阻塞Android的UI线程

================================================

方式二:使用Retrofit2
Retrofit官网
Retrofit2快速入门
建议直接使用Retrofit2

Gson

步骤如下:
1.引入retrofit2相关依赖(其中包括Gson转换器,用于返回JSON数据转化为Java对象)
2.创建一个API接口,用于定义业务需要的各种网络请求
3.创建retrofit实例
4.发送请求并处理返回结果

打开build.gradle.kts文件加入依赖

dependencies {
    implementation("com.google.code.gson:gson:2.11.0")
    implementation("com.squareup.retrofit2:retrofit:2.11.0")
    implementation("com.squareup.retrofit2:converter-gson:2.11.0")
}

由于日常开发所使用的站点接口一般是本地构建(通常是http的形式),而Android 9.0以上限制了明文的网络请求,非加密的请求都会被系统禁止掉。如果当前应用的请求是htttp请求,而非https请求,这样就会被Android系统禁止该请求,会出现类似java.net.UnknownServiceException: CLEARTEXT communication to xxxx.com not permitted by network security policy等错误提示

AndroidManifest.xml文件的application节点增加如下一行

android:usesCleartextTraffic="true"

在这里插入图片描述

先搭建一个本地测试站点,这里以https://demo.com为例
其中https://demo.com/site/user是根据idname获取用户信息的接口地址

请求响应如下

{"id":1001,"name":"buyue"}

MainActivity.kt代码如下

package com.demo.composestudy

import android.content.ContentValues.TAG
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            showUI()
        }

    }
}


data class User(val id: Int, val name: String)

interface ApiService{
    @GET("site/user")
    fun getUser(@Query("id") id: Int, @Query("name") name: String): Call<User>
}




@Composable
fun showUI(){
    var resultstring by remember { mutableStateOf("") }

    Column(){
        Button(
            onClick = {

                var url = "https://demo.com";
                var retrofit = Retrofit.Builder()
                    .baseUrl(url)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()

                var apiService = retrofit.create(ApiService::class.java)

                apiService.getUser(1,"buyue").enqueue(object : Callback<User>{
                    override fun onResponse(call: Call<User>, response: Response<User>) {
                        var user = response.body()
                        Log.d(TAG,user.toString())

                        resultstring = "ID:" + user?.id + "\nName:" + user?.name

                    }
                    override fun onFailure(call: Call<User>, t: Throwable) {
                        Log.d(TAG,"onFailure",t)
                    }
                })

        }){
        Text("点击进行请求")
    }

    Text(
        "$resultstring",
        Modifier.fillMaxWidth(),
        textAlign = TextAlign.Center,
        style = MaterialTheme.typography.titleMedium
    )
}
}


优化一下,封装统一返回值

修改https://demo.com/site/user请求响应如下

{"code":0,"message":"","data":{"id":1001,"name":"buyue"}}

调整MainActivity.kt代码如下

package com.demo.composestudy

import android.content.ContentValues.TAG
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            showUI()
        }

    }
}


data class ApiResponse<T>(val code: Int, val message: String? = null, val data: T? = null)
data class User(val id: Int, val name: String)


interface ApiService{
    @GET("site/user")
    fun getUser(@Query("id") id: Int, @Query("name") name: String): Call<ApiResponse<User>>
}




@Composable
fun showUI(){
    var resultstring by remember { mutableStateOf("") }

    Column(){
        Button(
            onClick = {

                var url = "https://demo.com"
                var retrofit = Retrofit.Builder()
                    .baseUrl(url)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()

                var apiService = retrofit.create(ApiService::class.java)

                apiService.getUser(1,"buyue").enqueue(object : Callback<ApiResponse<User>>{
                    override fun onResponse(call: Call<ApiResponse<User>>, response: Response<ApiResponse<User>>) {
                        //if (response.code() === 200) {
                        if (response.isSuccessful) {
                            // 请求成功,处理数据
                            val user = response.body()?.data
                            resultstring = "ID:" + user?.id + "\nName:" + user?.name
                        } else {
                            // 请求失败,处理错误信息
                            val message: String = response.message()
                            resultstring = message
                        }
                    }
                    override fun onFailure(call: Call<ApiResponse<User>>, t: Throwable) {
                        Log.d(TAG,"onFailure",t)
                    }
                })

        }){
        Text("点击进行请求")
    }

    Text(
        "$resultstring",
        Modifier.fillMaxWidth(),
        textAlign = TextAlign.Center,
        style = MaterialTheme.typography.titleMedium
    )

}

}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值