使用 OkHttp

  • 首先需要在项目中添加 OkHttp库 的依赖
dependencies {
    ......
    implementation 'com.squareup.okhttp3:okhttp:4.4.1'
}
  • 创建一个OkHttpClient实例
val client = OkHttpClient()
  • 创建一个Request对象
val request = Request.Builder().url("https://www.baidu.com").build()
  • 调用 OkHttpClient 的 newCall() 方法来创建一个Call对象,并调用它的 execute() 方法来发送请求,并获取从服务器返回的数据。
val response = client.newCall(request).execute()
  • 该response对象即为服务器返回的数据,可进行查看
response.body?.string()

 发起POST请求

  • 构建一个 Request Body 对象来存放待提交数据
val requestBody =  FormBody.Builder().add("username", "admin").add("password", "123456").build()
  • 在Request.Builder中调用  post()  方法,并将 Request Body 对象传入
val request = Request.Builder().url("https://www.baidu.com").post(requestBody).build()

全部代码如下:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sendRequestBtn = findViewById(R.id.sendRequestBtn)
        responseText = findViewById(R.id.responseText)

        sendRequestBtn.setOnClickListener {
            sendRequestWithOkHttp()
        }
    }

    private fun sendRequestWithOkHttp() {
        thread {
            try {
                val client = OkHttpClient()
                val requestBody =
                    FormBody.Builder().add("username", "admin").add("password", "123456").build()
                val request = Request.Builder().url("https://www.baidu.com").post(requestBody).build()
                val response = client.newCall(request).execute()
                val responseData = response.body?.string()
                if (responseData != null) showResponse(responseData)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

解析 JSON数据

(一) 使用JSONObject

  • 首先,调用OkHttp从网页获取数据
    private fun sendRequestWithOkHttp() {
        thread {
            try {
                //创建一个OkHttpClient实例
                val client = OkHttpClient()
                //创建要请求的对象
                val request = Request.Builder().url("").build()
                //调用实例的 Call 方法来发出请求,同时请求数据
                val response = client.newCall(request).execute()
                //获取请求的数据
                val responseData = response.body?.string()
                
                //当请求的数据不为空时,进行对应格式数据解析
                if (responseData != null) {
                    parseJSONWithJSONObject(responseData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
  • 通过JSONObject 来进行JSON格式数据解析,方法实现如下:
    private fun parseJSONWithJSONObject(jsonData: String) {
        try {
            //根据获取的数据类型,来创建对应的数据结构进行数据保存
            val jsonArray = JSONArray(jsonData)
            for (i in 0 until jsonArray.length()) {
                val jsonObject = jsonArray.getJSONObject(i)
                val id = jsonObject.getString("id")
                val version = jsonObject.getString("version")
                val name = jsonObject.getString("name")
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

根据获取的数据类型,来创建对应的数据结构进行数据保存。然后遍历数据结构,获取想要的数据。本例子使用的JSON数据如下所示:

[{"id":"5","version":"5.5","name":"Clash of Clans"},
{"id":"6","version":"7.0","name":"Boom Beach"},
{"id":"7","version":"3.5","name":"Clash Royale"}]

(二) 使用GSON 

Google提供的GSON开源库可以让解析JSON数据的工作简单到让你不敢想象的地步!

如果想要使用GSON需要首先添加GSON依赖库,GSON的强大之处在于将一段JSON格式的字符串自动映射成一个对象,从而不需要手动编写代码进行解析!!!!!

  • 添加GSON依赖库
dependencies {
    ...
    implementation 'com.squareup.okhttp3:okhttp:4.4.1'
    implementation 'com.google.code.gson:gson:2.8.6'
}
  • 如果一段JSON格式数据为
{"name":"Tom","age":20}

可以定义一个Person类,并加入 name 和 age 两个字段,然后调用 GSON 的 fromJson() 就可以自动解析成一个Person对象了。       

//需要先创建一个Gson实例
val gson = Gson()
val person = gson.fromJson(responseData, Person::class.java)

需要先创建一个Gson实例,然后调用 fromJson() .

  • 如果一段JSON格式数据为
[{"name":"Tom","age":20}, {"name":"Jack","age":25}, {"name":"Lily","age":22}]

需要借助 TypeToken 将期望解析成的数据类型传入 fromJson() 方法中,如下所示:

val typeOf = object : TypeToken<List<Person>>() {}.type
val people = gson.fromJson<List<Person>>(responseData,typeOf)

示例代码如下,新建一个App类,将JSON格式存储为App对象:

    private fun parseJSONWithGson(jsonData: String) {
        try {
            val gson = Gson()
            val typeOf = object : TypeToken<List<App>>() {}.type
            val appList = gson.fromJson<List<App>>(jsonData, typeOf)
            for (app in appList) {
                //业务逻辑
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

网络请求回调的实现方式 

一个项目中可能用到很多网络请求,如果每一次都需要编写相同代码,非常差劲。

通常情况下,将这些通用的网络操作提取到一个公共的类中,当需要网络请求时,调用方法即可。

需要网络请求回调的原因:

网络请求通常属于耗时操作,而sendHttpRequest()方法的内部并没有开启线程。如果我们在sendHttpRequest()方法中开启一个线程来发起HTTP请求,服务器响应的数据是无法进行返回的。这是由于所有的耗时逻辑都是在子线程里进行的,sendHttpRequest()方法会在服务器还没来得及响应的时候就执行结束了,当然也就无法返回响应的数据了。

 使用HTTP来进行网络请求

需要重新定义一个接口,进行回调。

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)
                    }
                }
                // 回调onFinish()方法
                listener.onFinish(response.toString())
            } catch (e: Exception) {
                e.printStackTrace()
                // 回调onError()方法
                listener.onError(e)
            } finally {
                connection?.disconnect()
            }
        }
    }
}

调用时还需要将 HttpCallbackListener 的实例传入,然后重写接口中的两个方法。

    private fun sendRequestWithHttpURLConnection() {
        val address = "https://www.baidu.com"
        HttpUtil.sendHttpRequest(address, object : HttpCallbackListener {
            override fun onFinish(response: String) {
                //从服务器返回的内容
                showResponse(response)
            }

            override fun onError(e: Exception) {
                //对异常情况进行处理
            }
        })
    }

    private fun showResponse(response: String) {
        responseText.text = response
    }

 调用时:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sendRequestBtn = findViewById(R.id.sendRequestBtn)
        responseText = findViewById(R.id.responseText)

        sendRequestBtn.setOnClickListener {
            sendRequestWithHttpURLConnection()
//            sendRequestWithOkHttp()
        }
    }

 使用OkHttp来进行网络请求

在公共类中定义如下:

object HttpUtil {
    fun sendOkHttpRequest(address: String, callback: okhttp3.Callback) {
        var connection: HttpURLConnection? = null
        try {
            val client = OkHttpClient()
            val request = Request.Builder().url(address).build()
            client.newCall(request).enqueue(callback)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    ......
}

sendOkHttpRequest()方法中有一个okhttp3.Callback参数,这个是OkHttp库中自带的回调接口,类似于我们刚才自己编写的HttpCallbackListener。然后在client.newCall()之后没有像之前那样一直调用execute()方法,而是调用了一个enqueue()方法,并把okhttp3.Callback参数传入。

OkHttp在 enqueue() 方法的内部已经帮我们开好子线程了,

    private fun sendRequestWithOkHttp() {

        val address = "https://www.baidu.com"
        HttpUtil.sendOkHttpRequest(address, object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                //对异常情况进行处理
            }

            override fun onResponse(call: Call, response: Response) {
                //得到从服务器返回的具体内容
                val responseData = response.body?.string()
            }

        })
    }

调用时:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sendRequestBtn = findViewById(R.id.sendRequestBtn)
        responseText = findViewById(R.id.responseText)

        sendRequestBtn.setOnClickListener {
//            sendRequestWithHttpURLConnection()
            sendRequestWithOkHttp()
        }
    }

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐