What are the characteristics of a good network framework?

  • request

Of course, this request is not just sending the request so simple, it includes a series of configuration related to the request is easy, whether the sending mode is flexible switching, whether the request header information is easy to handle, whether the request parameters are easy to operate, and so on

  • The response

A good network request framework certainly needs to improve our productivity and ensure the robustness of our programs, so what does the response body have to do with that? Whether entities that are easily converted to different requirements can return different types of structures. XML, JSON, TEXT, and so on

In general, it is easy to use, easy to extend, and readable


The purpose of,

  • background

There are no small number of network requests on the market now, from native HttpClient to OkHttp, Volley, xUtils are undoubtedly network requests to simplify, convenient, security and so on to improve the efficiency of development and the quality of the program. Retrofit, the OkHttp3 is encapsulated, the request API interface, the returned data combined with GSON and other convertors into direct development of the object, greatly improve our development efficiency, in order to solve the Android UI/ child thread responsible for the functional scene convenient switch, People started incorporating RxJava, which directly pushed Retrofit + OkHttp3 + RxJava into a popular web framework,

  • The status quo

Kotlin is a redefinition of Google’s approach to Android development, with its ambiguous attitude to not throwing away Java but declaring Kotlin as the language of choice. On the basis of jetpack framework, it has become another choice path for development in the new era. From the beginning to the end, Google has not launched an official design pattern for Android, and everyone has implemented their own design pattern from the aspects of high cohesion and low coupling, so as to make development simple, maintenance simple and program robust. Jetpack is Google’s first official production of design patterns, so do we need to use previous web frameworks on top of that? Are there better frameworks and combinations of frameworks that make our programs robust and easy to develop?

  • jetpack

The specifics of Jetpack are not explained here. Viewmodel-livedata has been recognized by the majority of developers. The combination of ViewModel and LiveData makes the controllability of data in Android become better and the coupling degree is lower. Simply put, the official observer mode is used in the whole data structure. Here will be combined with other frameworks to complete the network framework design

  • coroutines

Kotlin’s biggest change from Java is coroutines. Coroutines can completely replace RxJava, Thread, multilevel interface callback, etc., and have context and various patterns to meet various scenarios, which will not be explained here.

  • The new network request framework is encapsulated using several of the frameworks presented above

Two, composite framework

2.1 Adding a Dependency


//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. Fragments: fragments - KTX: 1.2.5'
    implementation "Androidx. Activity: activity - KTX: 1.1.0." "

    // Kotlin + coroutines
    implementation "Androidx. Work: work - the 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'

Copy the code

Add as required

2.2 Request helper classes

  • State management
enum class Status {
    SUCCESS,
    ERROR,
    LOADING
}
Copy the code
  • Request result handling class
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)}}Copy the code

2.3 Use Retrofit to create API interfaces and interface helper classes

Put interface management and requests in separate class files for ease of management

  • API interface
interface ApiService  {
    @GET("{page}")
    suspend fun getGirls(@Path("page") page: Int): Girls
}
Copy the code

Retrofit + OkHttp3 + coroutines + LiveData to create a network request framework

  • The API class calls the helper class
class ApiHelper(private val apiService: ApiService) {
    suspend fun getGirls(a) = apiService.getGirls(1)}Copy the code

2.4 Create a web framework request help class such as Retrofit and OkHttp

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)

}
Copy the code

With lazy loading, the required configuration is configured here and the function is called inline again. Check out the advantages of this.

2.5 Creating a Data Warehouse

The creation of data warehouse is to be able to process data here, there may be data that needs to be stored or reconstructed, but also to separate data processing and ViewModel, full-time data processing, ViewModel to do data turnover

class MainRepository(private val apiHelper: ApiHelper) {
    suspend fun getGirls(a) = apiHelper.getGirls()
}
Copy the code

2.6 the ViewModel

ViewModel is usually used to correspond to one or a group of logically related pages, making the data more independent and clear

class MainViewModel(private val mainRepository: MainRepository) : ViewModel() {
    fun getGirls(a) = liveData(Dispatchers.IO) {
        emit(Resource.loading(null))
        try {
            emit(Resource.success(mainRepository.getGirls()))
        } catch (e: Exception) {
            emit(Resource.error(e.message, null))}}}Copy the code

2.7 Create a ViewMdoel factory to create ViewMdoel

The advantage of this is that you can pass parameters and so on

class ViewModelFactory(private val apiHelper: ApiHelper) : ViewModelProvider.Factory {
    override fun 
        create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
            return MainViewModel(
                MainRepository(apiHelper)
            ) as T
        }
        throw IllegalArgumentException("Unknown class name")}}Copy the code

2.8 Creating an Interface Initialization Helper Class

Clear interface initialization management together, easy to view

object NetWorkHelper {
    val apiService =
        ServiceCreator.createService(ApiService::class.java)
}

Copy the code

2.9 the use of

Initialize in an Activity or Fragment

  • Initialize the
 mainViewModel =
            ViewModelProviders.of(this, ViewModelFactory(ApiHelper(NetWorkHelper.apiService))).get(MainViewModel::class.java)

Copy the code
  • Using the data

Clear callback status, handling different scenarios

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()
                    }
                }
            }
        })
Copy the code

Third, summary

In the development of better interface Databing and other components, more elegant development, for data processing ViewMdoel benefits really too much, you can learn more about,

Download the Demo