增加离线地图下载流程
This commit is contained in:
19
app/src/main/java/com/navinfo/omqs/Constant.kt
Normal file
19
app/src/main/java/com/navinfo/omqs/Constant.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.navinfo.omqs
|
||||
|
||||
class Constant {
|
||||
companion object {
|
||||
/**
|
||||
* 服务器地址
|
||||
*/
|
||||
const val SERVER_ADDRESS = "http://fastmap.navinfo.com/drdc/"
|
||||
|
||||
const val DEBUG = true
|
||||
|
||||
const val message_status_late = "预约,待发送"
|
||||
const val message_status_send_over = "已发送"
|
||||
const val message_version_right_off = "1" //立即发送
|
||||
|
||||
const val MESSAGE_PAGE_SIZE = 30 //消息列表一页最多数量
|
||||
}
|
||||
|
||||
}
|
||||
8
app/src/main/java/com/navinfo/omqs/OMQSApplication.kt
Normal file
8
app/src/main/java/com/navinfo/omqs/OMQSApplication.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package com.navinfo.omqs
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class OMQSApplication : Application() {
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.navinfo.omqs.model
|
||||
package com.navinfo.omqs.bean
|
||||
|
||||
data class LoginUser(
|
||||
data class LoginUserBean(
|
||||
var username: String = "",
|
||||
var password: String = ""
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.navinfo.omqs.bean
|
||||
|
||||
data class OfflineMapCityBean(
|
||||
val id: String,
|
||||
val fileName: String,
|
||||
val name: String,
|
||||
val url: String,
|
||||
val version: Long,
|
||||
val fileSize: Long,
|
||||
var currentSize:Long = 0,
|
||||
var status:Int = NONE
|
||||
) {
|
||||
companion object Status{
|
||||
const val NONE = 0 //无状态
|
||||
const val WAITING = 1 //等待中
|
||||
const val LOADING = 2 //下载中
|
||||
const val PAUSE = 3 //暂停
|
||||
const val ERROR = 4 //错误
|
||||
const val DONE = 5 //完成
|
||||
const val UPDATE = 6 //有新版本要更新
|
||||
}
|
||||
fun getFileSizeText(): String {
|
||||
return if (fileSize < 1024.0)
|
||||
"$fileSize B"
|
||||
else if (fileSize < 1048576.0)
|
||||
"%.2f K".format(fileSize / 1024.0)
|
||||
else if (fileSize < 1073741824.0)
|
||||
"%.2f M".format(fileSize / 1048576.0)
|
||||
else
|
||||
"%.2f M".format(fileSize / 1073741824.0)
|
||||
}
|
||||
}
|
||||
94
app/src/main/java/com/navinfo/omqs/hilt/GlobalModule.kt
Normal file
94
app/src/main/java/com/navinfo/omqs/hilt/GlobalModule.kt
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.navinfo.omqs.hilt
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.navinfo.omqs.Constant
|
||||
import com.navinfo.omqs.OMQSApplication
|
||||
import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
|
||||
import dagger.Lazy
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* 全局单例 注入对象
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class GlobalModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideApplication(application: Application): OMQSApplication {
|
||||
return application as OMQSApplication
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入 网络OKHttp 对象
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient {
|
||||
return OkHttpClient.Builder().addInterceptor(interceptor)
|
||||
.connectTimeout(60, TimeUnit.SECONDS).writeTimeout(5, TimeUnit.MINUTES)
|
||||
.readTimeout(5, TimeUnit.MINUTES).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入 OHHttp log
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
|
||||
return HttpLoggingInterceptor {
|
||||
if (Constant.DEBUG) {
|
||||
Log.e("jingo", it)
|
||||
}
|
||||
}.apply {
|
||||
level = if (Constant.DEBUG) {
|
||||
HttpLoggingInterceptor.Level.BODY
|
||||
} else {
|
||||
HttpLoggingInterceptor.Level.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideRetrofit(
|
||||
client: Lazy<OkHttpClient>,
|
||||
converterFactory: GsonConverterFactory,
|
||||
): Retrofit {
|
||||
val retrofitBuilder = Retrofit.Builder()
|
||||
.baseUrl(Constant.SERVER_ADDRESS)
|
||||
.client(client.get())
|
||||
.addConverterFactory(converterFactory)
|
||||
|
||||
return retrofitBuilder.build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGson(): Gson = Gson()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGsonConverterFactory(gson: Gson): GsonConverterFactory {
|
||||
return GsonConverterFactory.create(gson)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideNetworkService(retrofit: Retrofit): RetrofitNetworkServiceAPI {
|
||||
return retrofit.create(RetrofitNetworkServiceAPI::class.java)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.navinfo.omqs.hilt
|
||||
|
||||
import android.util.Log
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.omqs.ui.activity.map.MainViewModel
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ActivityRetainedComponent
|
||||
import dagger.hilt.android.scopes.ActivityRetainedScoped
|
||||
|
||||
@InstallIn(ActivityRetainedComponent::class)
|
||||
@Module
|
||||
class MainActivityModule {
|
||||
|
||||
@ActivityRetainedScoped
|
||||
@Provides
|
||||
fun providesMapController(): NIMapController = NIMapController()
|
||||
|
||||
/**
|
||||
* 实验失败,这样创建,viewmodel不会在activity销毁的时候同时销毁
|
||||
*/
|
||||
// @ActivityRetainedScoped
|
||||
// @Provides
|
||||
// fun providesMainViewModel(mapController: NIMapController): MainViewModel {
|
||||
// Log.e("jingo", "MainViewModel 被创建")
|
||||
// return MainViewModel(mapController)
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.navinfo.omqs.hilt
|
||||
|
||||
import com.navinfo.omqs.http.NetworkService
|
||||
import com.navinfo.omqs.http.NetworkServiceImpl
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
abstract class NetworkServiceModule {
|
||||
|
||||
@Binds
|
||||
abstract fun bindNetworkService(networkServiceImpl: NetworkServiceImpl): NetworkService
|
||||
}
|
||||
53
app/src/main/java/com/navinfo/omqs/http/NetResult.kt
Normal file
53
app/src/main/java/com/navinfo/omqs/http/NetResult.kt
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 密封类里面可以有若干个子类,这些子类如果要继承密封类,则必须和密封类在同一个文件里
|
||||
*/
|
||||
13
app/src/main/java/com/navinfo/omqs/http/NetworkService.kt
Normal file
13
app/src/main/java/com/navinfo/omqs/http/NetworkService.kt
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.navinfo.omqs.http
|
||||
|
||||
import com.navinfo.omqs.bean.OfflineMapCityBean
|
||||
|
||||
/**
|
||||
* 网络访问 业务接口
|
||||
*/
|
||||
interface NetworkService {
|
||||
/**
|
||||
* 获取离线地图城市列表
|
||||
*/
|
||||
suspend fun getOfflineMapCityList():NetResult<List<OfflineMapCityBean>>
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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的作用一致,可以用于添加多个不确定的参数,类似@QueryMap,Map的key作为表单的键,Map的value作为表单的值。
|
||||
*/
|
||||
// @FormUrlEncoded
|
||||
// @POST("api/dog")
|
||||
// fun postCall(@Field("token") token: String?): Call<Any?>?
|
||||
|
||||
/**
|
||||
* 当有多个不确定参数时,我们可以使用@FieldMap注解,@FieldMap与@Field的作用一致,可以用于添加多个不确定的参数,类似@QueryMap,Map的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/png:png图片格式
|
||||
以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 : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式
|
||||
另外一种常见的媒体格式是上传文件之时使用的:
|
||||
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.navinfo.omqs.ui.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.databinding.ActivityMainBinding
|
||||
|
||||
/**
|
||||
* 地图主页面
|
||||
*/
|
||||
class MainActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private val viewModel by viewModels<MainViewModel>()
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
|
||||
//关联生命周期
|
||||
binding.lifecycleOwner = this
|
||||
//给xml转递对象
|
||||
binding.mainActivity = this
|
||||
//给xml传递viewModel对象
|
||||
binding.viewModel = viewModel
|
||||
//初始化地图
|
||||
viewModel.initMap(this, binding.mapView.mainActivityMap)
|
||||
//让viewModel监听activity生命周期
|
||||
lifecycle.addObserver(viewModel)
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开个人中菜单
|
||||
*/
|
||||
fun openMenu() {
|
||||
binding.mainActivityDrawer.open()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.navinfo.omqs.ui.activity
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.collect.library.map.NIMapView
|
||||
|
||||
class MainViewModel : ViewModel(), DefaultLifecycleObserver {
|
||||
/**
|
||||
* 地图控制器
|
||||
*/
|
||||
private lateinit var mapController: NIMapController
|
||||
|
||||
/**
|
||||
* 初始化地图
|
||||
*/
|
||||
fun initMap(context: Context, mapView: NIMapView) {
|
||||
mapController = NIMapController(context = context, mapView = mapView)
|
||||
|
||||
}
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
super.onStart(owner)
|
||||
//开启定位
|
||||
mapController.locationLayerHandler.startLocation()
|
||||
}
|
||||
|
||||
override fun onPause(owner: LifecycleOwner) {
|
||||
mapController.mMapView.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
mapController.mMapView.onDestroy()
|
||||
//结束定位
|
||||
mapController.locationLayerHandler.stopLocation()
|
||||
}
|
||||
|
||||
override fun onResume(owner: LifecycleOwner) {
|
||||
mapController.mMapView.onResume()
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击我的位置,回到我的位置
|
||||
*/
|
||||
fun onClickLocationButton() {
|
||||
mapController.locationLayerHandler.animateToCurrentPosition()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.navinfo.omqs.ui.activity
|
||||
package com.navinfo.omqs.ui.activity.login
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
@@ -6,6 +6,8 @@ import androidx.activity.viewModels
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.databinding.ActivityLoginBinding
|
||||
import com.navinfo.omqs.ui.activity.map.MainActivity
|
||||
import com.navinfo.omqs.ui.activity.PermissionsActivity
|
||||
|
||||
/**
|
||||
* 登陆页面
|
||||
@@ -35,6 +37,6 @@ class LoginActivity : PermissionsActivity() {
|
||||
fun onClickLoginButton() {
|
||||
val intent = Intent(this@LoginActivity, MainActivity::class.java)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
// finish()
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.navinfo.omqs.ui.activity
|
||||
package com.navinfo.omqs.ui.activity.login
|
||||
|
||||
import android.view.View
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.navinfo.omqs.model.LoginUser
|
||||
import com.navinfo.omqs.bean.LoginUserBean
|
||||
|
||||
class LoginViewModel : ViewModel() {
|
||||
val loginUser: MutableLiveData<LoginUser> = MutableLiveData()
|
||||
val loginUser: MutableLiveData<LoginUserBean> = MutableLiveData()
|
||||
|
||||
init {
|
||||
loginUser.value = LoginUser(username = "admin", password = "123456")
|
||||
loginUser.value = LoginUserBean(username = "admin", password = "123456")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18,6 +18,5 @@ class LoginViewModel : ViewModel() {
|
||||
fun onClick(view: View) {
|
||||
loginUser.value!!.username = "admin2"
|
||||
loginUser.postValue(loginUser.value)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.navinfo.omqs.ui.activity.map
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.databinding.ActivityMainBinding
|
||||
import com.navinfo.omqs.ui.activity.BaseActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* 地图主页面
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : BaseActivity() {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private val viewModel by viewModels<MainViewModel>()
|
||||
|
||||
//注入地图控制器
|
||||
@Inject
|
||||
lateinit var mapController: NIMapController
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
|
||||
//初始化地图
|
||||
mapController.init(this, binding.mapView.mainActivityMap)
|
||||
//关联生命周期
|
||||
binding.lifecycleOwner = this
|
||||
//给xml转递对象
|
||||
binding.mainActivity = this
|
||||
//给xml传递viewModel对象
|
||||
binding.viewModel = viewModel
|
||||
// lifecycle.addObserver(viewModel)
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
//开启定位
|
||||
mapController.locationLayerHandler.startLocation()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mapController.mMapView.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mapController.mMapView.onDestroy()
|
||||
mapController.locationLayerHandler.stopLocation()
|
||||
Log.e("jingo","MainActivity 销毁")
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mapController.mMapView.onResume()
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开个人中菜单
|
||||
*/
|
||||
fun openMenu() {
|
||||
binding.mainActivityDrawer.open()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.navinfo.omqs.ui.activity.map
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.scopes.ActivityRetainedScoped
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* 创建Activity全局viewmode
|
||||
*/
|
||||
@HiltViewModel
|
||||
class MainViewModel @Inject constructor(
|
||||
private val mapController: NIMapController,
|
||||
) : ViewModel() {
|
||||
|
||||
|
||||
/**
|
||||
* 点击我的位置,回到我的位置
|
||||
*/
|
||||
fun onClickLocationButton() {
|
||||
mapController.locationLayerHandler.animateToCurrentPosition()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
Log.e("jingo","MainViewModel 被释放了")
|
||||
super.onCleared()
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.navinfo.omqs.ui.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.databinding.FragmentFirstBinding
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass as the default destination in the navigation.
|
||||
*/
|
||||
class FirstFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentFirstBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
|
||||
_binding = FragmentFirstBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.buttonFirst.setOnClickListener {
|
||||
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.navinfo.omqs.ui.fragment.offlinemap
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
|
||||
/**
|
||||
* 离线地图主页面,viewpage适配器
|
||||
*/
|
||||
class OfflineMapAdapter(activity: FragmentActivity) :
|
||||
FragmentStateAdapter(activity) {
|
||||
private val stateFragment = OfflineMapStateListFragment()
|
||||
private val cityListFragment = OfflineMapCityListFragment()
|
||||
override fun getItemCount(): Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> stateFragment
|
||||
else ->
|
||||
cityListFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.navinfo.omqs.ui.fragment.offlinemap
|
||||
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.BR
|
||||
import com.navinfo.omqs.bean.OfflineMapCityBean
|
||||
import com.navinfo.omqs.databinding.AdapterOfflineMapCityBinding
|
||||
import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
|
||||
import com.navinfo.omqs.ui.other.BaseViewHolder
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* 离线地图城市列表 RecyclerView 适配器
|
||||
*/
|
||||
|
||||
class OfflineMapCityListAdapter @Inject constructor() :
|
||||
BaseRecyclerViewAdapter<OfflineMapCityBean>() {
|
||||
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
|
||||
var binding: ViewDataBinding = holder.dataBinding
|
||||
//立刻刷新UI,解决闪烁
|
||||
// binding.executePendingBindings()
|
||||
binding.setVariable(BR.cityBean, data[position])
|
||||
(binding as AdapterOfflineMapCityBinding).offlineMapDownloadBtn.setOnClickListener {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return R.layout.adapter_offline_map_city
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.navinfo.omqs.ui.fragment.offlinemap
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.navinfo.omqs.databinding.FragmentOfflineMapCityListBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
/**
|
||||
* 离线地图城市列表
|
||||
*/
|
||||
@AndroidEntryPoint
|
||||
class OfflineMapCityListFragment : Fragment() {
|
||||
private var _binding: FragmentOfflineMapCityListBinding? = null
|
||||
private val viewModel by viewModels<OfflineMapCityListViewModel>()
|
||||
private val binding get() = _binding!!
|
||||
private val adapter: OfflineMapCityListAdapter by lazy { OfflineMapCityListAdapter() }
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentOfflineMapCityListBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
_binding!!.offlineMapCityListRecyclerview.layoutManager = layoutManager
|
||||
_binding!!.offlineMapCityListRecyclerview.adapter = adapter
|
||||
viewModel.cityListLiveData.observe(viewLifecycleOwner) {
|
||||
adapter.refreshData(it)
|
||||
}
|
||||
viewModel.getCityList()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
Log.e("jingo","OfflineMapCityListFragment onDestroyView")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.navinfo.omqs.ui.fragment.offlinemap
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.navinfo.omqs.http.NetResult
|
||||
import com.navinfo.omqs.http.NetworkService
|
||||
import com.navinfo.omqs.bean.OfflineMapCityBean
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* 离线地图城市列表viewModel
|
||||
*/
|
||||
@HiltViewModel
|
||||
class OfflineMapCityListViewModel @Inject constructor(
|
||||
private val networkService: NetworkService,
|
||||
@ApplicationContext val context: Context
|
||||
) : ViewModel() {
|
||||
|
||||
val cityListLiveData = MutableLiveData<List<OfflineMapCityBean>>()
|
||||
|
||||
/**
|
||||
* 去获取离线地图列表
|
||||
*/
|
||||
fun getCityList() {
|
||||
viewModelScope.launch {
|
||||
when (val result = networkService.getOfflineMapCityList()) {
|
||||
is NetResult.Success -> {
|
||||
cityListLiveData.postValue(result.data!!)
|
||||
}
|
||||
is NetResult.Error -> {
|
||||
Toast.makeText(context, "${result.exception.message}", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
is NetResult.Failure -> {
|
||||
Toast.makeText(context, "${result.code}:${result.msg}", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
NetResult.Loading -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.navinfo.omqs.ui.fragment.offlinemap
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.navinfo.omqs.databinding.FragmentOfflineMapBinding
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* 离线地图
|
||||
*/
|
||||
class OfflineMapFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentOfflineMapBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentOfflineMapBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
//禁止滑动,因为页面在抽屉里,和抽屉的滑动有冲突
|
||||
binding.offlineMapViewpager.isUserInputEnabled = false
|
||||
//创建viewpager2的适配器
|
||||
binding.offlineMapViewpager.adapter = activity?.let { OfflineMapAdapter(it) }
|
||||
//绑定viewpager2与tabLayout
|
||||
TabLayoutMediator(
|
||||
binding.offlineMapTabLayout,
|
||||
binding.offlineMapViewpager
|
||||
) { tab, position ->
|
||||
when (position) {
|
||||
0 -> tab.text = "下载管理"
|
||||
1 -> tab.text = "城市列表"
|
||||
}
|
||||
}.attach()
|
||||
|
||||
//处理返回按钮
|
||||
binding.offlineMapBack.setOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
Log.e("jingo","OfflineMapFragment onDestroyView")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.navinfo.omqs.ui.fragment.offlinemap
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.navinfo.omqs.databinding.FragmentOfflineMapBinding
|
||||
import com.navinfo.omqs.databinding.FragmentOfflineMapStateListBinding
|
||||
|
||||
|
||||
class OfflineMapStateListFragment : Fragment() {
|
||||
private var _binding: FragmentOfflineMapStateListBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentOfflineMapStateListBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
Log.e("jingo","OfflineMapStateListFragment onDestroyView")
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,42 @@
|
||||
package com.navinfo.omqs.ui.fragment
|
||||
package com.navinfo.omqs.ui.fragment.personalcenter
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.databinding.FragmentSecondBinding
|
||||
import com.navinfo.omqs.databinding.FragmentPersonalCenterBinding
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass as the second destination in the navigation.
|
||||
* 个人中心
|
||||
*/
|
||||
class SecondFragment : Fragment() {
|
||||
class PersonalCenterFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentSecondBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private var _binding: FragmentPersonalCenterBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
|
||||
_binding = FragmentSecondBinding.inflate(inflater, container, false)
|
||||
_binding = FragmentPersonalCenterBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.buttonSecond.setOnClickListener {
|
||||
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
|
||||
Log.e("jingo", "NIMapController PersonalCenterFragment onViewCreated")
|
||||
binding.root.setNavigationItemSelectedListener {
|
||||
when (it.itemId) {
|
||||
R.id.personal_center_menu_offline_map ->
|
||||
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.navinfo.omqs.ui.other
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
/**
|
||||
* RecyclerView 适配器基础类
|
||||
*/
|
||||
abstract class BaseRecyclerViewAdapter<T>(var data: List<T> = listOf()) :
|
||||
RecyclerView.Adapter<BaseViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
|
||||
return BaseViewHolder(
|
||||
DataBindingUtil.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
viewType,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
|
||||
fun refreshData(newData:List<T>){
|
||||
this.data = newData
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.navinfo.omqs.ui.other
|
||||
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
/**
|
||||
* dataBinding viewHolder 基类
|
||||
*/
|
||||
open class BaseViewHolder(var dataBinding: ViewDataBinding) :
|
||||
RecyclerView.ViewHolder(dataBinding.root) {
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.navinfo.omqs.ui.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Rect
|
||||
import android.opengl.ETC1.getHeight
|
||||
import android.opengl.ETC1.getWidth
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ProgressBar
|
||||
|
||||
|
||||
/**
|
||||
* 带文字提示的进度条
|
||||
*/
|
||||
class MyProgressBar : ProgressBar {
|
||||
private lateinit var mPaint: Paint
|
||||
private var text: String = ""
|
||||
private var rate = 0f
|
||||
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
|
||||
initView()
|
||||
}
|
||||
|
||||
constructor(context: Context?) : super(context) {
|
||||
initView()
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
mPaint = Paint()
|
||||
mPaint.isAntiAlias = true
|
||||
mPaint.color = Color.BLUE
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun setProgress(progress: Int) {
|
||||
setText(progress)
|
||||
super.setProgress(progress)
|
||||
}
|
||||
|
||||
private fun setText(progress: Int) {
|
||||
rate = progress * 1.0f / this.getMax()
|
||||
val i = (rate * 100).toInt()
|
||||
text = "$i%"
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
val rect = Rect()
|
||||
mPaint.getTextBounds(text, 0, text.length, rect)
|
||||
// int x = (getWidth()/2) - rect.centerX();
|
||||
// int y = (getHeight()/2) - rect.centerY();
|
||||
var x = (width * rate).toInt()
|
||||
if (x == width) {
|
||||
// 如果为百分之百则在左边绘制。
|
||||
x = width - rect.right
|
||||
}
|
||||
val y: Int = 0 - rect.top
|
||||
mPaint.textSize = 22f
|
||||
canvas.drawText(text, x.toFloat(), y.toFloat(), mPaint)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user