网络数据的获取
这里以聚合数据获取数据为例
拼接网址:
http://v.juhe.cn/toutiao/index?type=junshi&key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size=1
?:开始拼接请求参数,接口地址和请求参数之间用?连接
&:如果有多个请求,参数与参数之间使用&连接
使用原生的方式下载数据
/**使用原生api下载*/
private fun loadWithOriginal(){
Thread{
//准备下载地址
val urlString = "http://v.juhe.cn/toutiao/index?type=junshi&key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size=1"
val url = URL(urlString)
//发起连接URLConnection
val urlConnection = url.openConnection() as HttpURLConnection
urlConnection.requestMethod = "Get"
//urlConnection.doInput = true
//接受数据
val inputStream =urlConnection.inputStream
//使用缓存方式读取对应的字符流数据 -> 加快读取速率
val bufferedReader = BufferedReader(InputStreamReader(inputStream))
//读取缓存流里面的数据
val jsonString = bufferedReader.readLine()
//在真正的项目中,不是显示获取的字符串,而是将获取的数据转换成对应的对象
//将获取的json格式的字符串 转化为对应的对象类型
val newData = Gson().fromJson(jsonString,News::class.java)
//显示文本
runOnUiThread {
textView.text = jsonString
}
}.start()
}
通过URLConnection发起连接
通过HttpURLConnection还可以获取连接的请求头、请求体。
通过requestMethod可以对请求方式进行设置
另外
image.png
通过url就可以获取许多信息:
比如文件名、主机名、路径、端口号、协议、参数……
使用原生的方式下载图片
思路:从网络中下载图片到文件(filesDir/cacheDir),然后再从文件中读取图片
private fun loadImageWithOriginal(){
Thread{
val urlString = ""https://spoonacular.com/cdn/ingredients_250x250/kale""
val url = URL(urlString)
val connection = url.openConnection() as HttpURLConnection
val inputStream = connection.inputStream
//创建字节输入流
val byteInputStream = BufferedInputStream(inputStream)
//创建文件的输出流
val imageFile = File(cacheDir,"dog.jpg")
val fos = FileOutputStream(imageFile)
//将网路的输入流 写入到文件的输出流中
val bufferArray = ByteArray(1024)//一次读入1024字节
while (byteInputStream.read(bufferArray)!=-1){
fos.write(bufferArray,0,bufferArray.size)
}
fos.flush()
//从文件里面读取图片
val bitmap = BitmapFactory.decodeFile(imageFile.path)
runOnUiThread {
imageView.setImageBitmap(bitmap)
}
}
}
创建连接对象的不同代码方式:如果没有将connection转成HttpURLConnection就调用getInputStream
因为每次写入的数据为1024个字节,但是读取的数据可能不是1024个字节,所以这里实验的结果显示的图片是乱的,下面针对这一bug进行修复
bug修复在读取文本中使用的是BufferedReader(写BufferedWriter),但这里是读取图片(二进制数据)所以有所不同BufferedInputStream(写BufferedOutputStream)。
image.png image.pngcacheDir与filesDir:
前者是临时保存,而后者是一直存在。
实现下载进度
通过打印获取key与value的值
获取到我们想要的信息 image.png 进度显示 验证效果
使用Okhttp下载数据
导入依赖:implementation("com.squareup.okhttp3:okhttp:4.9.1")
OkHttpClient在build的过程中,可以对其进行一系列设置,比如connectTimeout色设置连接超时时间(不设置的话会有默认值)。
同步请求(注意:同步请求会阻塞主线程)
/**使用OkHttp下载*/
private fun loadDataWithOkHttp(){
//创建一个OkHttpClient对象
val okHttpClient = OkHttpClient.Builder()
//设置连接超时时间
.connectTimeout(10,TimeUnit.SECONDS)
.build()
//创建一个请求 Request
val urlString = "http://v.juhe.cn/toutiao/index?type=junshi&key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size=1"
val request = Request.Builder()
.get()
.url(urlString)
.build()
//使用Call发起请求(同步、异步)
//同步执行
val call = okHttpClient.newCall(request)
val response = call.execute()
if (response.isSuccessful){
response.body?.let {
//获取json格式的字符串
val jsonString = it.string()
//使用gson转化为具体的对象
val newData = Gson().fromJson(jsonString,News::class.java)
}
}
}
//异步执行
/**使用OkHttp下载*/
private fun loadDataWithOkHttp(){
//创建一个OkHttpClient对象
val okHttpClient = OkHttpClient.Builder()
//设置连接超时时间
.connectTimeout(10,TimeUnit.SECONDS)
.build()
//创建一个请求 Request
val urlString = "http://v.juhe.cn/toutiao/index?type=junshi&key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size=1"
val request = Request.Builder()
.get()
.url(urlString)
.build()
//使用Call发起请求(同步、异步)
//同步执行
val call = okHttpClient.newCall(request)
//异步执行请求
call.enqueue(object :Callback{
override fun onFailure(call: Call, e: IOException) {
Log.v("ppp","${e.message}")
}
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful){
response.body?.let {
//获取json格式的字符串
val jsonString = it.string()
runOnUiThread {
textView.text = jsonString
}
//使用gson转化为具体的对象
val newData = Gson().fromJson(jsonString,News::class.java)
}
}
}
})
使用OkHttp下载图片
/**使用OkHttp下载图片*/
private fun loadImageWithOkHttp(){
val urlString = "http://v.juhe.cn/toutiao/index?type=junshi&key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size="
val okHttpClient = OkHttpClient()
val request = Request.Builder()
.url(urlString)
.get()
.build()
val call = okHttpClient.newCall(request)
call.enqueue(object :Callback{
override fun onFailure(call: Call, e: IOException) {
e.message
}
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful){
response.body?.let {
val inputStream = it.byteStream()
//需要进度 网络的输入流 ->文件->Bitmap
//不需要进度
val bitmap = BitmapFactory.decodeStream(inputStream)
runOnUiThread {
imageView.setImageBitmap(bitmap)
}
}
}
}
})
}
这里需注意,如果是做完整项目的话需要在前方创建过程中判断缓存中是否存在图片(可以以完整的路径作为名字),后面在下载的时候也需像前方一样先放入文件再从文件中读取。
使用Retrofit访问数据
前面讲解的方法都是以前的比较繁琐的方式,下面这个方式才是目前最流行的最简易的方式——Retrofit
Retrofit使用超简单,但难以明白其内部实现,其实其内部实现就是上面提到的原生系列操作
使用retrofit访问数据的基本步骤
1、创建数据类
2、定义网络访问的方法 接口文件
3、创建接口对应的实例对象
导入相关依赖
//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//retrofit-gson转换器
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//Coroutine
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0'
//ViewModel
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0-alpha02")
implementation "androidx.activity:activity-ktx:1.2.0"
implementation "androidx.fragment:fragment-ktx:1.3.0"
1、创建数据类
前面已经使用插件完成了数据类的创建
2、定义网络访问的方法 接口文件(通常命名采用xxxService,xxxApi)
常用注解就两种@Get,@Post,在注解中放入除基地址的其他参数
/**
*@Description
*@Author PC
*@QQ 1578684787
*/
interface NewsApi {
//http://v.juhe.cn/toutiao/index?type=junshi&key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size=1
@GET("toutiao/index?type=junshi&key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size=1")
suspend fun fetchNew():News
//动态参数
@GET("toutiao/index?key=2aba5ed71d6d00fe39c7eb5012b128ed&page_size=10")
suspend fun fetchNews(@Query("type")NewsType:String):News
//系列动态参数
@GET("toutiao/index?key=2aba5ed71d6d00fe39c7eb5012b128ed")
suspend fun fetchNews2(@QueryMap query: Map<String,String>):News
}
3、创建接口所对应的实例对象
将基地址放入retrofit的创建中
/**使用Retrofit下载*/
private fun loadDataWithRetrofit(){
//创建Retrofit对象
val retrofit = Retrofit.Builder()
.baseUrl("http://v.juhe.cn/")
.addConverterFactory(GsonConverterFactory.create())
.build()
//获取接口对应的实现类对象 自动创建
val api = retrofit.create(NewsApi::class.java)
lifecycleScope.launch(Dispatchers.IO) {
//val data = api.fetchNew()
val datas = api.fetchNews2(mapOf(Pair("type","tiyu"),Pair("page_size","10")))
datas.result.datas.forEach {
Log.v("xxx","${it.title}")
}
}
}
使用retrofit下载二进制数据(图片,音频,视频)
NewsApi /**使用Retrofit下载图片*/
private fun loadImageWithRetrofit(){
val retrofit = Retrofit.Builder()
.baseUrl("https//t7.baidu.com/it/")
.build()
val api = retrofit.create(NewsApi::class.java)
lifecycleScope.launch (Dispatchers.IO){
val responseBody = api.fetchMedia()
//如果需要下载进度 输入流 -> 文件 ->Bitmap
val inputStream = responseBody.byteStream()
//不关心进度
val bytes = responseBody.bytes()
val bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.size)
withContext(Dispatchers.Main){
imageView.setImageBitmap(bitmap)
}
}
}
responseBody还能获取其他信息
image.png
网友评论