增加离线地图下载流程

This commit is contained in:
squallzhjch
2023-03-30 10:50:20 +08:00
parent 97a48237ba
commit 3a80a4ee5d
129 changed files with 1590 additions and 13847 deletions

View File

@@ -0,0 +1,53 @@
package com.navinfo.omqs.http
/**
* Created by Mayokun Adeniyi on 23/05/2020.
*/
/**
* 网络返回封装
*/
/**
* 在类名之前使用sealed关键字将类声明为密封类。
* 密封类仅在编译时限制类型集来确保类型安全的重要性。
* 密封类隐式是一个无法实例化的抽象类。
*/
/**
* 二:密封类所具有的特性和与别的类具有不同之处
①Sealed class密封类 是一个有特定数量子类的类,看上去和枚举有点类似,所不同的是,在枚举中,我们每个类型只有一个对象(实例);而在密封类中,同一个类可以拥有几个对象。
②Sealed class密封类的所有子类都必须与密封类在同一文件中
③Sealed class密封类的子类的子类可以定义在任何地方并不需要和密封类定义在同一个文件中
④Sealed class密封类没有构造函数不可以直接实例化只能实例化内部的子类
*/
/**
* 如何获取密封类里面的函数方法
* 只能创建密封类子类对象 通过密封类的子类对象调用密封类里的函数方法
*/
sealed class NetResult<out R> {
data class Success<out T>(val data: T?) : NetResult<T>()
data class Failure(val code: Int, val msg: String) : NetResult<Nothing>()
data class Error(val exception: Exception) : NetResult<Nothing>()
object Loading : NetResult<Nothing>()
/**
* 密封类通常与表达when时一起使用。 由于密封类的子类将自身类型作为一种情况。
因此密封类中的when表达式涵盖所有情况从而避免使用else子句。
*/
override fun toString(): String {
return when (this) {
is Success<*> -> "网络访问成功返回正确结果Success[data=$data]"
is Failure -> "网络访问成功返回错误结果Failure[$msg]"
is Error -> "网络访问出错 Error[exception=$exception]"
is Loading -> "网络访问中 Loading"
}
}
}
/**
* 密封类里面可以有若干个子类,这些子类如果要继承密封类,则必须和密封类在同一个文件里
*/

View File

@@ -0,0 +1,13 @@
package com.navinfo.omqs.http
import com.navinfo.omqs.bean.OfflineMapCityBean
/**
* 网络访问 业务接口
*/
interface NetworkService {
/**
* 获取离线地图城市列表
*/
suspend fun getOfflineMapCityList():NetResult<List<OfflineMapCityBean>>
}

View File

@@ -0,0 +1,35 @@
package com.navinfo.omqs.http
import com.navinfo.omqs.bean.OfflineMapCityBean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject
/**
* 网络访问业务接口的具体实现
*/
class NetworkServiceImpl @Inject constructor(
private val netApi: RetrofitNetworkServiceAPI,
) : NetworkService {
/**
* 获取离线地图城市列表
*/
override suspend fun getOfflineMapCityList(): NetResult<List<OfflineMapCityBean>> =
//在IO线程中运行
withContext(Dispatchers.IO) {
return@withContext try {
val result = netApi.retrofitGetOfflineMapCityList()
if (result.isSuccessful) {
if (result.code() == 200) {
NetResult.Success(result.body())
} else {
NetResult.Failure(result.code(), result.message())
}
} else {
NetResult.Failure(result.code(), result.message())
}
} catch (e: Exception) {
NetResult.Error(e)
}
}
}

View File

@@ -0,0 +1,237 @@
package com.navinfo.omqs.http
import androidx.lifecycle.LiveData
import com.navinfo.omqs.bean.OfflineMapCityBean
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Streaming
import retrofit2.http.Url
import java.util.concurrent.Flow
/**
* retrofit2 网络请求接口
*/
interface RetrofitNetworkServiceAPI {
/**
* 在 Retrofit2 中,可以使用不同类型的返回值来获取 API 调用的结果。以下是 Retrofit2 支持的一些常见返回类型:
1. `Call<T>`:表示一个异步请求,其中 `T` 是 API 响应的类型,通常是一个自定义的数据类。使用 `enqueue` 方法来执行异步请求,并在回调中处理响应。
2. `Response<T>`:表示一个同步请求的响应,其中 `T` 是 API 响应的类型。使用 `execute` 方法来执行同步请求,并返回一个 `Response` 对象,其中包含了响应的状态码、响应头和响应体等信息。
3. `Observable<T>`:表示一个 RxJava 的 Observable 对象,其中 `T` 是 API 响应的类型。使用 `subscribe` 方法来执行请求,并在 onNext 回调中处理响应。
4. `Single<T>`:表示一个 RxJava 的 Single 对象,其中 `T` 是 API 响应的类型。使用 `subscribe` 方法来执行请求,并在 onSuccess 回调中处理响应。
5. `Completable`:表示一个 RxJava 的 Completable 对象,用于执行没有响应体的 API 调用。使用 `subscribe` 方法来执行请求,并在 onComplete 回调中处理响应。
6. `Flowable<T>`:表示一个 RxJava 的 Flowable 对象,其中 `T` 是 API 响应的类型。类似于 Observable但支持背压处理。
7. `Deferred<T>`:表示一个 Kotlin 的 Deferred 对象,其中 `T` 是 API 响应的类型。使用 `await` 方法来执行请求,并返回响应的结果。
8. `LiveData<Response<T>>`:表示一个 LiveData 对象,其中 `T` 是 API 响应的类型。使用 `observe` 方法来执行请求,并在回调中处理响应。
总之Retrofit2 支持多种返回类型,开发者可以根据项目需求选择合适的方式来处理 API 响应结果。
*/
/**
* 获取离线地图城市列表
*/
@GET("/drdc/MapDownload/maplist")
suspend fun retrofitGetOfflineMapCityList(): Response<List<OfflineMapCityBean>>
/**
* 下载文件
*/
@Streaming
@GET
suspend fun retrofitDownLoadFile(@Url url: String):Response<ResponseBody>
/**
* @FormUrlEncoded 请求格式注解请求实体是一个From表单每个键值对需要使用@Field注解
@Field 请求参数注解,提交请求的表单字段,必须要添加,而且需要配合@FormUrlEncoded使用
“token” 参数字段,与后台给的字段需要一致
String 声明的参数类型
token 实际参数表示后面token的取值作为"token"的值
Post请求如果有参数需要在头部添加@FormUrlEncoded注解表示请求实体是一个From表单每个键值对需要使用@Field注解使用@Field添加参数这是发送Post请求时提交请求的表单字段必须要添加的而且需要配合@FormUrlEncoded使用若为在头部添加@FormUrlEncoded注解会抛出如下异常
当有多个不确定参数时,我们可以使用@FieldMap注解@FieldMap与@Field的作用一致可以用于添加多个不确定的参数类似@QueryMapMap的key作为表单的键Map的value作为表单的值。
*/
// @FormUrlEncoded
// @POST("api/dog")
// fun postCall(@Field("token") token: String?): Call<Any?>?
/**
* 当有多个不确定参数时,我们可以使用@FieldMap注解@FieldMap与@Field的作用一致可以用于添加多个不确定的参数类似@QueryMapMap的key作为表单的键Map的value作为表单的值。
*/
// @FormUrlEncoded
// @POST("api/dog")
// open fun postCall(@FieldMap map: Map<String?, Any?>?): Call<Any?>?
/**
* @GET("v7/weather/now")
Call<Wth_now_out> getCall(@QueryMap Map<String, Object> map);
*/
// @GET("v7/weather/now")
// open fun getCall(@QueryMap map: Map<String?, Any?>?): Call<Wth_now_out?>?
/**
*@Query 请求参数注解用于Get请求中的参数
“location”/“key” 参数字段,与后台给的字段需要一致
*/
// @GET("v7/weather/now")
// open fun getCall(@QueryMap map: Map<String?, Any?>?): Call<Wth_now_out?>?
/**
* @FieldMap 请求参数注解,与@Field作用一致用于不确定表单参数
Map<String, Object> map 通过Map将不确定的参数传入相当于多个Field参数
适用于Post请求的还有一个注解@Body@Body可以传递自定义类型数据给服务器多用于post请求发送非表单数据比如用传递Json格式数据它可以注解很多东西比如HashMap、实体类等我们来看看它用法
特别注意:@Body注解不能用于表单或者支持文件上传的表单的编码即不能与@FormUrlEncoded和@Multipart注解同时使用
*/
// @POST("")
// open fun getPsotDataBody(@Body body: RequestBody?): Call<Any?>?
/**
* @Path
使用第一个get请求网址
*/
// @GET("v7/weather/{time}")
// open fun getCall(@Path("time") time: String?,@QueryMap map: Map<String?, Any?>?): Call<Wth_now_out?>?
/**
* @QueryMap get请求方法参数的注解上面已经解释了这里就不重复讲
@Path 请求参数注解用于Url中的占位符{},在网址中的参数
@Path注解用于Url中的占位符{},在网址中的参数,如上面 @GET(“v7/weather/{time}”)的time通过{}占位符来标记time使用@Path注解传入time的值注意有的Url既有占位符又有"?"后面的键值对,其实@Query和@Path两者是可以共用的。在发起请求时{time}会被替换为方法中第二个参数的值time。
*/
// Map<String ,Object> map = new HashMap<>()Map<String ,Object> map = new HashMap<>();
// map.put("location","101010100");
// map.put("key","a5cf6ab782a14013b08fb92a57dd2f72");
// Call<Wth_now_out> call = apiService.getCall("now",map);
/**
* 最终{time}会被替换为now,此时形成的牵绊部分Url为https://devapi.qweather.com/v7/weather/now剩余**?号**后面的Url由@Query传入。
*/
/**
* @HTTP
@HTTP注解的作用是替换@GET、@POST、@PUT、@DELETE、@HEAD以及更多拓展功能
如可通过此注解代替@POST注解实现post请求如下
method 表示请求的方法区分大小写这里的值retrofit不会再做任何处理必须要保证正确
path 网络请求地址路径
hasBody 是否有请求体boolean类型
除请求接口部分的方法有变,别的部分与正常使用@POST请求一致另外需要注意在使用@HTTP注解实现post请求时若含有请求体那么对应的标识注解@FormUrlEncoded一定要加上若为别的请求体那么就添加与之对应的标识注解。
@HTTP注解可以通过method字段灵活设置具体请求方法通过path设置网络请求地址用的比较少。使用方法与设置的请求方法种类一致。
*/
// @FormUrlEncoded
// @POST("api/dog")
// Call<Object> postCall(@FieldMap Map<String,Object> map);
//
// @FormUrlEncoded
// @HTTP(method = "POST",path = "api/dog", hasBody = true)
// Call<Object> postCall1(@FieldMap Map<String,Object> map);
/**
* @Url
如果需要重新地址接口地址,可以使用@Url将地址以参数的形式传入即可。如果有@Url注解时GET传入的Url必须省略。不然会抛出如下异常。
*/
//错误的
// @FormUrlEncoded
// @POST("api/dog")
// open fun postCall(@Url url: String?, @FieldMap map: Map<String?, Any?>?): Call<Any?>?
//正确的
// @FormUrlEncoded
// @POST
// open fun postCall(@Url url: String?, @FieldMap map: Map<String?, Any?>?): Call<Any?>?
/**
* @Streaming
* @Streaming 表示响应体的数据用流的方式返回,使用于返回数据比较大,该注解在下载大文件时特别有用
*/
// @Streaming
// @POST("gists/public")
// open fun getStreamingBig(): Call<ResponseBody?>?
/**
* @Multipart、@part、@PartMap
* @Multipart 表示请求实体是一个支持文件上传的表单,需要配合@Part和@PartMap使用适用于文件上传
@Part 用于表单字段,适用于文件上传的情况,@Part支持三种类型RequestBody、MultipartBody.Part、 任意类型
@PartMap 用于多文件上传, 与@FieldMap和@QueryMap的使用类似
*/
// @Multipart
// @POST("user/followers")
// open fun getPartData(@Part("name") name: RequestBody?, @Part file: Part?): Call<ResponseBody?>?
/**
* 代码使用逻辑:
* 首先声明类型通过MediaType实现类型的声明此处使用的时文本类型然后会根据该类型转化为RequestBody对象此处使用的参数委RequestBody对象相当于讲周润发以文本格式转换委RequestBody对象最终上传时与name形成键值对。
*/
// //声明类型,这里是文字类型
// MediaType textType = MediaType.parse("text/plain");
// //根据声明的类型创建RequestBody,就是转化为RequestBody对象
// RequestBody name = RequestBody.create(textType, "周润发");
////创建文件,这里演示图片上传
// File file = new File("文件路径");
// if (!file.exists()) {
// file.mkdir();
// }
////将文件转化为RequestBody对象
////需要在表单中进行文件上传时就需要使用该格式multipart/form-data
// RequestBody imgBody = RequestBody.create(MediaType.parse("image/png"), file);
////将文件转化为MultipartBody.Part
////第一个参数上传文件的key第二个参数文件名第三个参数RequestBody对象
// MultipartBody.Part filePart = MultipartBody.Part.createFormData("key", file.getName(), imgBody);
/**
* 对于文件类型的上传我们一般使用MultipartBody.Part类型上传在上面讲两个参数设置好后然后调用接口使用请求方法即可
* 此种格式属于文本与文件混合发送的格式。
*/
// var partDataCall: Call<ResponseBody?>? = retrofit.create(Api::class.java).getPartData(name, filePart)
/**
* @PartMap的使用与@FieldMap和@QueryMap的使用类似用于多文件上传我们直接看代码
*/
// @Multipart
// @POST("user/followers")
// open fun getPartMapData(@PartMap map: Map<String?, Part?>?): Call<ResponseBody?>?
// File file1 = new File("文件路径");
// File file2 = new File("文件路径");
// if (!file1.exists()) {
// file1.mkdir();
// }
// if (!file2.exists()) {
// file2.mkdir();
// }
// RequestBody requestBody1 = RequestBody.create(MediaType.parse("image/png"), file1);
// RequestBody requestBody2 = RequestBody.create(MediaType.parse("image/png"), file2);
// MultipartBody.Part filePart1 = MultipartBody.Part.createFormData("file1", file1.getName(), requestBody1);
// MultipartBody.Part filePart2 = MultipartBody.Part.createFormData("file2", file2.getName(), requestBody2);
//
// Map<String,MultipartBody.Part> mapPart = new HashMap<>();
// mapPart.put("file1",filePart1);
// mapPart.put("file2",filePart2);
/**
* 有关MediaType方法
* 概述MediaType即是Internet Media Type互联网媒体类型也叫做MIME类型在Http协议消息头中使用Content-Type来表示具体请求中的媒体类型信息。也就是说MediaType在网络协议的消息头里面叫做Content-Type它使用两部分的标识符来确定一个类型是为了表明我们传的东西是什么类型。
常见的媒体格式类型如下:
text/html HTML格式
text/plain :纯文本格式
text/xml XML格式
image/gif gif图片格式
image/jpeg jpg图片格式
image/pngpng图片格式
以application开头的媒体格式类型
application/xhtml+xml XHTML格式
application/xml XML数据格式
application/atom+xml Atom XML聚合格式
application/json JSON数据格式
application/pdf pdf格式
application/msword Word文档格式
application/octet-stream 二进制流数据(如常见的文件下载、上传)
application/x-www-form-urlencoded 中默认的encTypeform表单数据被编码为key/value格式发送到服务器表单默认的提交数据的格式
另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data 需要在表单中进行文件上传时,就需要使用该格式
*/
}