amitshekhariitbhu / Fast-Android-Networking

🚀 A Complete Fast Android Networking Library that also supports HTTP/2 🚀
https://outcomeschool.com
Apache License 2.0
5.68k stars 956 forks source link

Kotlin Coroutine Support #392

Open GulajavaMinistudio opened 5 years ago

GulajavaMinistudio commented 5 years ago

Fast Android Networking have been support RxJava for beginning. And can you add support for Kotlin Coroutine in this library ?

Or any tips and tricks about how to use Fast Android Networking with Kotlin Coroutine ?

Pfuster12 commented 5 years ago

If I'm not mistaken, you can create a synchronous request, so you can wrap it in a coroutine scope.

CoroutineScope(Dispatcher.Main).launch { synchronousRequest() }

heskadon commented 3 years ago

Is there anyone has an example of how to implement Fast Android Networking with Kotlin Coroutine?

yogeshpaliyal commented 3 years ago

I hope this will help


/*
CREATED BY : yogesh ON 07/08/20 10:58 AM
*/

open class BaseCaller {

    val params: HashMap<String, String> by lazy {
        HashMap<String, String>()
    }

    val files: HashMap<String, File?> by lazy {
        HashMap<String, File?>()
    }

    suspend fun hitApiGet(
        api: String,
        params: HashMap<String, String>? = null, checkAuthentication: Boolean = true
    ): Resource<BaseApiModel> {
        return hitApiGet(api, params, BaseApiModel::class.java,checkAuthentication)
    }

    suspend fun <T> hitApiGet(
        api: String,
        params: HashMap<String, String>? = null,
        objectType: Class<T>, checkAuthentication: Boolean = true
    ): Resource<T> {
        val request = AndroidNetworking.get(api)
            .addQueryParameter(params)
            .addHeaders(getHeader())
            .build()

        return request.fetch(objectType,checkAuthentication)
    }

    suspend fun hitApiUpload(
        api: String,
        params: HashMap<String, String>? = null,
        files: HashMap<String, File?>? = null, checkAuthentication: Boolean = true
    ): Resource<BaseApiModel> {
        return hitApiUpload(api, params, files, BaseApiModel::class.java, checkAuthentication)
    }

    suspend fun <T> hitApiUpload(
        api: String,
        params: HashMap<String, String>? = null,
        files: HashMap<String, File?>? = null,
        objectType: Class<T>, checkAuthentication: Boolean = true
    ): Resource<T> {
        val request = AndroidNetworking.upload(api)
            .addMultipartParameter(params)
            .addMultipartFile(files)
            .setOkHttpClient(OkHttpClient())
            .addHeaders(getHeader())
            .build()

        return request.fetch(objectType,checkAuthentication)
    }

    private suspend fun <T> ANRequest<*>.fetch(objectType: Class<T>,checkAuthentication: Boolean): Resource<T> = withContext(Dispatchers.IO){
        val response = executeForObject(BaseApiModel::class.java)
        try {
            if (response.isSuccess) {
                if (response.result is BaseApiModel) {
                    val baseApiModel = response.result as BaseApiModel
                    if (baseApiModel.code == 200) {
                        if (objectType.isAssignableFrom(BaseApiModel::class.java))
                            return@withContext Resource.success<T>(baseApiModel as T, baseApiModel.message)
                        val formatted = Gson().fromJson(baseApiModel.data, objectType)
                        return@withContext  Resource.success<T>(formatted, baseApiModel.message)
                    } else {
                        return@withContext  onGettingError(ANError().apply {
                            errorCode = baseApiModel.code
                            this.errorBody = Gson().toJson(baseApiModel).toString()
                        },checkAuthentication)
                    }
                } else {
                    return@withContext  Resource.error<T>("Some error occurred")
                }
            }
        }catch (e:Exception){
            e.printStackTrace()
            return@withContext  Resource.error<T>("Some error occurred")
        }
        return@withContext  onGettingError(response.error,checkAuthentication)
    }

    suspend fun hitApi(
        api: String,
        params: HashMap<String, String>? = null, checkAuthentication: Boolean = true,headers: HashMap<String, String>? = null
    ): Resource<BaseApiModel> {
        return hitApi(api, params, BaseApiModel::class.java, checkAuthentication,headers)
    }

    suspend fun <T> hitApi(
        api: String,
        params: HashMap<String, String>? = null,
        objectType: Class<T>, checkAuthentication: Boolean = true, headers: HashMap<String, String>? = null
    ): Resource<T> {

        val request = AndroidNetworking.post(api)
            .addBodyParameter(params)
            .addHeaders(getHeader())
            .addHeaders(headers)
            .build()

        return request.fetch(objectType,checkAuthentication)
    }

    private fun <T> onGettingError(anError: ANError, checkAuthentication: Boolean): Resource<T> {
         if (anError.errorCode == 401) {
             if (checkAuthentication)
                 MyApplication.getInstance().logout()
             return Resource.error<T>("User Logout")
         } else if (anError.errorCode != 0) {
            // received error from server
            // error.getErrorCode() - the error code from server
            // error.getErrorBody() - the error body from server
            // error.getErrorDetail() - just an error detail
            //Log.d(TAG, "onError errorCode : " + anError.getErrorCode());
            //Log.d(TAG, "onError errorBody : " + anError.getErrorBody());
            //Log.d(TAG, "onError errorDetail : " + anError.getErrorDetail());
            // get parsed error object (If ApiError is your class)
            try {
                LogHelper.logD("Error",anError.errorBody)
                val apiError = anError.getErrorAsObject(BaseApiModel::class.java)
                return Resource.error<T>(apiError.message)
            } catch (e: Exception) {
                return Resource.error<T>("Parsing Error")
                e.printStackTrace()
            }
        } else {
            // error.getErrorDetail() : connectionError, parseError, requestCancelledError
            //Log.d(TAG, "onError errorDetail : " + anError.getErrorDetail());
            return when (anError.errorDetail) {
                ANConstants.REQUEST_CANCELLED_ERROR -> Resource.error<T>("Request Cancelled")
                ANConstants.CONNECTION_ERROR -> Resource.error<T>("No internet connected")
                else -> Resource.error<T>("Some Error occurred")
            }
        }
    }

    protected fun getHeader(): HashMap<String, String> {
        val map = HashMap<String, String>()
        map.put("platform", "A")
        map.put("os_version", Build.VERSION.SDK_INT.toString())
       // map["device_id"] = getDeviceId()
       // map["X-localization"] = PreferenceLocaleStore(MyApplication.getInstance(), Locale(Languages.ENGLISH)).getLocale().language
        map["app_version"] = BuildConfig.VERSION_NAME
        map["time"] = System.currentTimeMillis().toString()
        map["timezone"] = TimeZone.getDefault().id
        map["Accept"] = "application/json"
        val token = MyApplication.getInstance().getLoginToken()
        if (!token.trim().isBlank())
            map["Authorization"] = "Bearer $token"
        return map
    }

}