kine

Additional

Language
Kotlin
Version
v1.0 (Oct 6, 2020)
Created
Aug 21, 2020
Updated
Oct 6, 2020
Owner
AnkitAgrawal967
Contributor
AnkitAgrawal967
1
Activity
Badge
Generate
Download
Source code

Blurb

Kine (Kotlin I/O Networking Extensions)

A simple and powerful HTTP networking library for Kotlin/Android.

Medium Blog on it here : https://medium.com/@ankit9673/kine-networking-in-2020-ae83bdc686b3 and same on my blog : https://makingmoneyfromonline.com/2020/08/23/kine-networking-in-2020/

Features

  • Supports HTTP GET/POST/PUT/DELETE/HEAD/PATCH
  • Supports synchronous and asynchronous requests
  • Download file with progress
  • Get Image as bitmap from url
  • MultiPart Upload
  • Response caching in disk
  • OkHttp cache control full support
  • Supports OkHttp with ability to write your own Httpclient
  • Cancel any in-flight request
  • Request timeout with retry policy
  • App Wide Configuration using Kine with support for common Headers , base Url for all request
  • Log manager with option to turn logging off for per request and App wide
  • Supports response deserialization into POJO/POKO with Gson or Moshi
  • Supports reactive programming via RxJava 2.x / RxJava 3.x
  • Supports kotlin coroutines
  • Supports live data
  • Supports ability to handle any type of response with custom converter option

Upcoming Planned Features

  • Support for jackson parser
  • Bitmap caching and auto previous request cancellation for ImageLoading
  • New interceptor api for manipulating request pre execute

Installation

Library is available on jcenter

Gradle

repositories {
    jcenter()
}

dependencies {
    compile 'com.kine:kine:1.0.0.0' //for JVM
    compile 'com.kine:kine-json:2.8.6.0' //for json support(do not use this dependency in android project)
    compile 'com.kine:kine-android:1.0.0.0' //for Android
    compile 'com.kine:kine-rxjava2:2.2.19.0' //for RxJava2 support
    compile 'com.kine:kine-rxjava3:3.0.6.0' //for RxJava3 support
    compile 'com.kine:kine-coroutine:1.3.8.0' //for Coroutine support
    compile 'com.kine:kine-livedata:1.3.8.0' //for LiveData support
    compile 'com.kine:kine-gson:2.8.6.0' //for Gson support
    compile 'com.kine:kine-moshi:1.9.3.0' //for Moshi support
    compile 'com.kine:kine-okhttp:4.8.1.0' //for OkHttp support
    compile 'com.kine:kine-okhttplegacy:3.12.12.0' //for Legacy OkHttp support(API 9)
    compile 'com.kine:kine-imageloader:1.0.0.0' //for Imageloading support
}
Note: Kine will autodetect if android,okhttp,gson or moshi dependency are there and set appropriate client, converter or main thread callback you don't need to specify them,if both moshi and gson are there, kine will add moshi first(converter are always called by add order so if you have both dependency and trying to parse it using gson it won't work). To override this behaviour you can set them using Kine.builder() as shown below

Usage

Kine Configuration

Kine.Builder()
            .headers(hashMapOf()) // common headers for all app requests
            .client(OkHttpKineClient()) // common client to use for all requests
            .converter(GsonConverter()) // gson converter for parsing response
            .connectionChecker(SimpleConnectionChecker(context!!)) // a simple connection checker for no internet
            .baseUrl(ConfigUtils.dummyBaseUrl) // a base url for all requests
            .logLevel(LogLevel.ERROR) // logs to display according to level
            .disableAllLogs(true) // disable all logging for all requests
            .build()
Note: Options provided with individual KineRequest will always take priority over Kine global configuration except for headers , headers will always be added to individual request headers specified by the user

Kine requests can be made with KineRequest class or using one of the String or other extension methods. If you specify a callback the call is asynchronous, if you don't its synchronous. Exception will be thrown in synchronous (you need to catch them). Exception will be delivered to onError callback in asynchronous except for user error like not specifying a converter and expecting a parsed response.

Get Json

"https://example/api/test".httpGet().responseAs(JSONObject::class.java,{ response->
               val response =  response.body
           }, { e ->
               e.printStackTrace()
           })
// for sync
val response =  "https://example/api/test".httpGet().responseAs(JSONObject::class.java)

Get String

"https://example/api/test".httpGet().responseAs(String::class.java,{ response->
               val response =  response.body
           }, { e ->
               e.printStackTrace()
           })
// for sync
val response =  "https://example/api/test".httpGet().responseAs(String::class.java)

Get JsonArray

"https://example/api/test".httpGet().responseAs(JSONArray::class.java,{ response->
               val list =  Gson().fromJsonArray<Post>(response.body.toString())
           }, { e ->
               e.printStackTrace()
           })
// for sync
val response =  "https://jsonplaceholder.typicode.com/posts".httpGet().responseAs(JSONArray::class.java)

Gson (requires kine-gson dependency) / Moshi (requires kine-moshi dependency)

"https://example/api/test".httpGet().responseAs(User::class.java,{ response->
               val user:User =  response.body
           }, { e ->
               e.printStackTrace()
           })
// for sync
val response =  "https://example/api/test".httpGet().responseAs(User::class.java)

RxJava2 (requires kine-rxjava2 dependency) / RxJava3 (requires kine-rxjava3 dependency)

Single

"https://example/api/test".httpGet().toSingle(clazz)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : SingleObserver<KineResponse<T>?> {
                override fun onSubscribe(d: Disposable) {
                }
                override fun onSuccess(response: KineResponse<T>) {
                    val response = response.body.toString()
                }
                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
            })

Flowable

"https://example/api/test".httpGet().toFlowable(clazz)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : FlowableSubscriber<KineResponse<T>> {

                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
                override fun onSubscribe(s: Subscription) {
                    s.request(1)
                }
                override fun onNext(response: KineResponse<T>) {
                    val response = response.body.toString()
                }
                override fun onComplete() {
                }
            })

Observable

 "https://example/api/test".httpGet().toObservable(clazz)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Observer<KineResponse<T>?> {
                override fun onError(e: Throwable) {
                    e.printStackTrace()
                }
                override fun onNext(response: KineResponse<T>) {
                    val response = response.body.toString()
                }
                override fun onComplete() {
                }
                override fun onSubscribe(d: Disposable) {
                }
            })

Kotlin Coroutine (requires kine-coroutine dependency)

 GlobalScope.launch(Dispatchers.Main) {
            val response = "https://example/api/test".httpGet().responseAsCoroutine(clazz)
        }

Download File

"https://example/api/test/files/test10Mb.db".downloadTo(
            File(Environment.getExternalStorageDirectory(),"test.db"),{downloaded,total->
// note the progress listener is not called on main thread it is always called on background thread 
// for async request and calling thread on sync request
                activity?.runOnUiThread {
                    val progress = "progress ${((downloaded*100)/total)}"
                }
            }, { response ->
                val savedPath = response.body?.path
            }, { e ->
                e.printStackTrace()
            })

Image Loading (requires kine-imageloader dependency)

Load Bitmap From Url

  "https://example/api/test/files/abc.png".loadBitmapResponseFromUrl( { response ->
            imageView!!.setImageBitmap(response.body)
        }, { e -> e.printStackTrace() })

Load Image from Url to ImageView

  imageView.loadImage("https://example/api/test/files/abc.png",placeHolderResId)

Cancelling request

Application

 Kine.cancelAllRequests() // cancels all request with clients set with Kine
 Kine.cancelAllRequests(tag) // cancels all request with that tag with clients 
 // set with Kine(note passing null will cancel all request)

Individual Request

  val client = OkHttpKineClient()
  "url".httpGet().client(client).responseAs(User::class.java)
  client.cancelAllRequests() // behaves same as above Kine cancel methods

MultiPart Image Upload

   KineRequest.upload("").addMultiPartParam("name","test",null).addMultiPartFileParam("tset",
   File("sdcard/test.apk"),null).setUploadListener { bytesWritten, total ->  }.responseAs(User::class.java,{ response->
   val response = response.body
     },{e->
           e.printStackTrace()
     })

Requirements

For Android

OkHttp 4x

  • Min SDK 21+(for OkHttpClient you can write your own client for supporting Api Version below it)
  • Java 8+

OkHttp 3x (legacy)

  • Min SDK 9+(for OkHttpClient you can write your own client for supporting Api Version below it)
  • Java 7+

For Kotlin/Java

  • Kotlin 1.4/Java 8+

R8 / Proguard

If you use R8/Proguard , you may need to add rules for Coroutines, RxJava2 RxJava3 OkHttp and Okio.

License

Copyright 2020 Kine

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.