一个好的网络框架须要有那些特色呢?java
固然这个请求不仅仅是发送请求这么简单,它包括请求相关的一系列配置是否简易、发送模式是否灵活切换、请求头信息是否易处理、请求参数是否易操做等等android
一个好的网络请求框架确定须要提升咱们的生产力,保证咱们程序的健壮性,那么响应体和这些又有什么关系呢? 容易转换成不一样需求的实体 是否能返回不一样类型的结构。xml、json、text等等git
总的来讲就是易使用、易扩展、可读性高github
市场上如今存在的网络请求不在少数,从原生的HttpClient 到 OkHttp、Volley、xUtils 无疑都是将网络请求简单化、方便、安全等用以提高开发的效率以及程序的质量。后面出现Retrofit ,将OkHttp3 进行了封装,将请求API 接口化,将返回的数据结合GSON等各类转换器转换为直接面向开发的对象,大大的提高了咱们的开发效率,为了解决Android UI/子线程 负责的功能场景方便切换,你们开始结合了RxJava, 这一操做直接将Retrofit + OkHttp3 + RxJava 组合的网络框架推上了热门写法,json
kotlin 的出现是Google 对于Android开发的从新定义,含糊不清的态度,既不丢弃Java又宣布kotlin 是首选语言。在次基础上结合jetpack框架,成了新时代开发的另外一条选择路径,从始至终Google 没有对Android推出过官方的设计模式,你们都是从高内聚、低耦合等方面推行着本身的设计模式,让开发简单、维护简单、程序健壮。jetpack是Google 对设计模式的首次官方制造,重点可想而知,那在这个基础上咱们还须要使用以前的网络框架吗?有没有更加优秀的框架以及框架的组合使得咱们的程序健壮、开发简易呢?设计模式
具体的jetpack不是这里解释的。其中ViewModel - LiveData 已经获得了广大开发者的承认,ViewModel 和LiveData 的结合,使得Android中数据可控性变得更好,耦合度更低,简单来讲是官方将观察者模式用于到了真个数据结构中,在这里也是将要结合其余框架来完成网络框架的设计api
kotlin较Java的最大变化就是kotlin推出的coroutines (协程),协程彻底能够替代RxJava, Thread、多级接口回调等,而且有上下文及各类模式来迎合各类场景,具体再也不这里解释,安全
//LifeCycle
implementation 'androidx.lifecycle:lifecycle-common:2.2.0'
implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0'
implementation 'android.arch.lifecycle:extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
//Retrofit
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.2.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation 'com.squareup.retrofit2:converter-scalars:2.6.2'
//Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7'
//Kotlin extensions for activity and fragments
implementation 'androidx.fragment:fragment-ktx:1.2.5'
implementation "androidx.activity:activity-ktx:1.1.0"
// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:2.3.4"
// optional - RxJava2 support
implementation "androidx.work:work-rxjava2:2.3.4"
// optional - GCMNetworkManager support
implementation "androidx.work:work-gcm:2.3.4"
// optional - Test helpers
androidTestImplementation "androidx.work:work-testing:2.3.4"
implementation 'org.conscrypt:conscrypt-android:2.2.1'
复制代码
具体根据需求添加markdown
enum class Status {
SUCCESS,
ERROR,
LOADING
}
复制代码
class Resource<out T>(val status: Status, val data: T?, val message: String?) {
companion object {
fun <T> success(data: T?) = Resource(Status.SUCCESS, data, null)
fun <T> error(msg: String?, data: T?) = Resource(Status.ERROR, data, msg)
fun <T> loading(data: T?) = Resource(Status.LOADING, data, null)
}
}
复制代码
将接口管理和请求放在不一样的类文件中,方便管理网络
interface ApiService {
@GET("{page}")
suspend fun getGirls(@Path("page") page: Int): Girls
}
复制代码
数据类将传到Demo中 Retrofit + OkHttp3 + coroutines + LiveData打造一款网络请求框架
class ApiHelper(private val apiService: ApiService) {
suspend fun getGirls() = apiService.getGirls(1)
}
复制代码
object ServiceCreator {
private val okHttpClient by lazy { OkHttpClient().newBuilder() }
private val retrofit: Retrofit by lazy {
val builder = Retrofit.Builder()
.baseUrl("https://gank.io/api/v2/data/category/Girl/type/Girl/page/1/count/")
.addConverterFactory(GsonConverterFactory.create())
val dispatcher = Dispatcher()
dispatcher.maxRequests = 1
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
okHttpClient
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(com.kpa.network.data.http.interceptor.HttpLoggingInterceptor())
.dispatcher(dispatcher)
builder.client(okHttpClient.build()).build()
}
fun <T> create(clazz: Class<T>): T = retrofit.create(clazz)
inline fun <reified T> createService(clazz: Class<T>): T =
create(clazz)
}
复制代码
使用懒加载,将须要的配置在此处配置好,inline 对函数再次调用,能够查一下这样用的优势。
数据仓库的建立是为了能在此到处理数据,可能存在须要存储或者重构的数据,也是将数据的处理和ViewModel分离开,专职作数据处理,ViewModel 作数据周转
class MainRepository(private val apiHelper: ApiHelper) {
suspend fun getGirls() = apiHelper.getGirls()
}
复制代码
通常在使用ViewModel 的时候都是于一个或者一组逻辑相关的页面对应,将数据更加独立、清晰
class MainViewModel(private val mainRepository: MainRepository) : ViewModel() {
fun getGirls() = liveData(Dispatchers.IO) {
emit(Resource.loading(null))
try {
emit(Resource.success(mainRepository.getGirls()))
} catch (e: Exception) {
emit(Resource.error(e.message, null))
}
}
}
复制代码
这样作的好处在于可随便传递参数等
class ViewModelFactory(private val apiHelper: ApiHelper) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
return MainViewModel(
MainRepository(apiHelper)
) as T
}
throw IllegalArgumentException("Unknown class name")
}
}
复制代码
清晰的将接口初始化管理在一块儿,方便查看
object NetWorkHelper {
val apiService =
ServiceCreator.createService(ApiService::class.java)
}
复制代码
在Activity、Fragment中 初始化
mainViewModel =
ViewModelProviders.of(this, ViewModelFactory(ApiHelper(NetWorkHelper.apiService))).get(MainViewModel::class.java)
复制代码
清晰的回调状态、处理不一样场景
mainViewModel.getGirls().observe(this, Observer {
it?.let { resource ->
when (resource.status) {
Status.SUCCESS -> {
recyclerView.visibility = View.VISIBLE
progressBar.visibility = View.GONE
resource.data?.let { girls -> renderList(girls) }
}
Status.ERROR -> {
progressBar.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
}
}
}
})
复制代码
在开发中上能够更好的接口Databing 等组件、更加优雅的开发,对于数据的处理ViewMdoel 的好处真的太多了,能够多了解一下,