How to use enque method in retrofit in Kotlin android - android

I am trying to get a response from web service using retrofit and kotlin language. but i am unable to call enque method .
This is retrofit client
class WebService() {
companion object {
fun createService(isAddToken: Boolean): WebServiceApi {
val logging = HttpLoggingInterceptor()
val httpClient = OkHttpClient.Builder()
var retrofit: Retrofit
httpClient.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
.header(CONTENT_TYPE, "application/json")
.header(API_USER_NAME, AUTH_USERNAME)
.header(API_PASSWORD, AUTH_PASSWORD)
.header(LANGUAGE_CODE, "en")
if (isAddToken) {
requestBuilder.header(TOKEN,
"" /*DataGenerator.getAuthToken(context)*/)
}
requestBuilder.method(original.method(), original.body())
val request = requestBuilder.build()
chain.proceed(request)
}
// set your desired log level
if (BuildConfig.DEBUG) {
logging.level = HttpLoggingInterceptor.Level.BODY
// add logging as last interceptor
httpClient.addInterceptor(logging)
}
// Timeout handling
val client = httpClient.readTimeout(20,
TimeUnit.SECONDS)
.connectTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.build()
if (BuildConfig.DEBUG) {
retrofit = Retrofit.Builder()
.baseUrl(WebServiceConstants.LIVE_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
} else {
retrofit = Retrofit.Builder()
.baseUrl(WebServiceConstants.LIVE_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
}
return retrofit.create(WebServiceApi::class.java);
}
}
}
This is code of MainActivity where i am calling api on button
val parameterOTP = SendParameterOTP()
parameterOTP.phoneNumber = phoneNumber
var serviceAPI = WebService.createService(false)
serviceAPI.enque() \\Unable to understand how i call enques**
I tried example using rxjava ,it works fine .But i want to use enque method as i want to implement custom callback for retrying . Please help

try to use this:
val call = createService(isAddToken).methodNameInWebServiceApi(params)
call.enqueue(object : Callback<ResponseObject> {
override fun onFailure(call: Call<ResponseObject>?, t: Throwable?) {
Log.e("erroe", "")
}
override fun onResponse(call: Call<ResponseObject>?, response: Response<ResponseObject>?) {
}
})

i am provide retrofit class and api call using kotlin and make changes according to rxjava in your side.
class ApiClient {
companion object {
val BASE_URL = "https://simplifiedcoding.net/demos/"
var retrofit: Retrofit? = null
fun getClient(): Retrofit? {
if (retrofit == null) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder().apply {
readTimeout(20, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS)
connectTimeout(20, TimeUnit.SECONDS)
addInterceptor(interceptor)
addInterceptor { chain ->
var request = chain.request()
request = request.newBuilder()
.build()
val response = chain.proceed(request)
response
}
}
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
}
}
then after used below code for api calling ..
var apiInterface: ApiInterface = ApiClient.getClient()!!.create(ApiInterface::class.java)
var hero: Call<List<Hero>>
hero = apiInterface.getData()
hero.enqueue(object : Callback<List<Hero>> {
override fun onFailure(call: Call<List<Hero>>?, t: Throwable?) {
closeDialog(dialog)
Toast.makeText(mContext, t?.message, Toast.LENGTH_SHORT).show()
Log.d("Error:::",t?.message)
}
override fun onResponse(call: Call<List<Hero>>?, response: Response<List<Hero>>?) {
mHeroDataList.clear()
if (response != null && response.isSuccessful && response.body() != null) {
closeDialog(dialog)
mHeroDataList .addAll(response.body()!!)
setAdapter(mHeroDataList)
}
}
})

app > build.gradle
// Retrofit
implementation ("com.squareup.retrofit2:retrofit:$retrofit_version") {
// exclude Retrofit’s OkHttp peer-dependency module and define your own module import
exclude module: "okhttp"
}
// OkHttp and a logging interceptor
implementation("com.squareup.okhttp3:okhttp:$okhttp_version")
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
project > build.gradle
buildscript {
...
ext.retrofit_version = '2.6.0'
ext.okhttp_version = '4.0.0'
...
}
package.name > external > ApiClient.kt
object ApiClient {
private const val BASE_URL = "https://test.apiary-mock.com/"
private var retrofit: Retrofit? = null
val apiClient: Retrofit
get() {
if (retrofit == null) {
val logging = HttpLoggingInterceptor()
logging.apply {
level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
}
val client: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit!!
}
}
Usage
val carRestService = ApiClient.apiClient.create(CarRestService::class.java)
Sources
exclude module
okhttp
okhttp-logging-interceptor

Related

When I use retrofit2, the app is just shut down

I used retrofit2 to call API. But, when I called it, my app was just shut down. There are not errors in the Logcat. I googled it, but there is not a solution.
And Retrofit2 and converter-gson version is 2.9.0. I set internet permission in AndroidManifest.xml
MainActivity.kt
private fun loadMembers() {
val retrofit = Retrofit.Builder()
.baseUrl(MemberAPI.base_domain)
.addConverterFactory(GsonConverterFactory.create())
.build()
val retrofitService = retrofit.create(MemberInterface::class.java)
retrofitService
.getMember(Constants.api_key)
.enqueue(object: Callback<Member> {
override fun onResponse(call: Call<Member>, response: Response<Member>) {
val members = response.body() as Member
var names = ""
for (member in members.response.body.items.item) {
names += "\n${member.empNm}"
}
binding.text.text = names
}
override fun onFailure(call: Call<Member>, t: Throwable) {
Toast.makeText(baseContext, "실패", Toast.LENGTH_LONG).show()
}
})
}
Interface.kt
interface MemberInterface {
#GET("{api_key}&numOfRows=5&pageNo=1&_type=json")
fun getMember(#Path("api_key") Key: String): Call<Member>
}
Youtube
Video
Try to add an interceptor so you can see all calls logs (headers, body, URLs, etc...). The crash could be related with the parse of the JSON response to the object Member.
Add OkHtpp to your grade dependencies:
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.2"
implementation "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2"
And after that, when you create your Retrofit instance, add the interceptor, should look something like this:
val httpClient = OkHttpClient.Builder()
val interceptor = HttpLoggingInterceptor()
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
httpClient.addInterceptor(interceptor)
httpClient.addInterceptor(Interceptor { chain: Interceptor.Chain ->
val original: Request = chain.request()
val request: Request = original.newBuilder()
.header("Content-Type", "application/json")
.method(original.method, original.body)
.build()
chain.proceed(request)
})
val okHttpClient = httpClient.build()
val retrofit = Retrofit.Builder()
.baseUrl(MemberAPI.base_domain)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()

Special character = gets converted into %3D after calling API using retrofit

I want to pass = sign in request params as string. It coverts into %3D upon calling api.
You need to use custom interceptor as below:
class MyInterceptor: Interceptor {
override fun intercept (chain: Interceptor.Chain): Response {
val request = chain.request()
val unEncodedStringUrl = request.url.toString().replace("%3D", "=")
var newRequest = request.newBuilder().url(unEcodedStringUrl).build()
return chain.proceed(newRequest)
}
}
And then use it for OkHttpClient of the retrofit:
fun getOkHttpClient(
myInterceptor: MyInterceptor,
loggingInterceptor: HttpLoggingInterceptor
): OkHttpClient {
return OkHttpClient().newBuilder().addInterceptor(myInterceptor).also {
if (BuildConfig.DEBUG) {
it.addInterceptor(loggingInterceptor)
}
}.build()
}
Finally, use this OkHttpClient for retrofit as below:
fun getRetrofit(moshi: Moshi): Retrofit {
return Retrofit.Builder()
.baseUrl(StaticConstants.baseUrl)
.client(getOkHttpClient())
.addConverterFactory(
MoshiConverterFactory.create(moshi)
)
.build()
}

I am using Retrofit 2.0. I want to handle all types of network errors and exceptions

my application crashes when I have no internet connection : I am looking for a method that handles any exception form the retrofit instance like server is not found exception Timeout No internet connection
RequestRepository : my repository which contain all my functions
class RequestRepository {
/** suspend function to get the result of token request*/
suspend fun getToken(userLoginModel: UserLoginModel): Response<TokenResponse> {
return ApiService.APILogin.getToken(userLoginModel)
}
ApiService : contain my Retofit instance
object ApiService {
private var token: String = ""
fun setToken(tk: String) {
token = tk
}
private val okHttpClient = OkHttpClient.Builder().connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS).addInterceptor { chain ->
val chainRequest = chain.request()
val requestBuilder = chainRequest.newBuilder()
.addHeader("authorization", "Token $token")
.method(chainRequest.method, chainRequest.body)
val request = requestBuilder.build()
chain.proceed(request)
}.build()
var gson = GsonBuilder()
.setLenient()
.create()
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl(LOGIN_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okHttpClient)
.build()
}
val API: WebServicesApi by lazy {
retrofit.create(WebServicesApi::class.java)
}
WebServicesApi : my interface which contain my requests
interface WebServicesApi {
/** get the token from the API*/
#POST("user/login/")
suspend fun getToken(#Body userLoginModel: UserLoginModel): Response<TokenResponse>
}
LoginViewModel : my viewModel class
class LoginViewModel(private val repository: RequestRepository) : ViewModel() {
var tokenResponse: MutableLiveData<Response<TokenResponse>> = MutableLiveData()
/** using coroutine in getToken function to get the token */
fun getToken(userLoginModel: UserLoginModel) {
viewModelScope.launch(Dispatchers.IO) {
val tResponse = repository.getToken(userLoginModel)
tokenResponse.postValue(tResponse)
Log.d(TAG, "getToken: ${userLoginModel.password}")
}
}
}
You can add a Interceptor for handle error like this:
class GlobalErrorInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
try {
val response = chain.proceed(request)
if (!response.isSuccessful) {
val statusCode = response.code
when (statusCode) {
//Your handle status code in here
}
}
return response
} catch (ex: IOException) {
// You can replace my code with your exception handler code
return Response.Builder().request(chain.request()).protocol(Protocol.HTTP_1_1)
.message("Can't connect!").code(500).body(
ResponseBody.create(
"application/json; charset=utf-8".toMediaTypeOrNull(),
""
)
).build()
}
}
}
And you must add this class to OkHttpBuider:
val httpBuilder = OkHttpClient.Builder()
......
httpBuilder.addInterceptor(GlobalErrorInterceptor())

Retrofit response is always null

I'm trying to get user name from gitHub Api but retrofit response return always null. When I'm trying to show user name in toast I see : null. I tried change retrofit path but it didn't work. Everything looks fine but I don't know why I get this error all the time.
interface GitHubApi{
#GET("/users/{user}")
fun getUser(#Path("user") user: String): Call<User>
companion object Factory {
fun getClient(): GitHubApi {
val url = "https://api.github.com/"
val interceptor = HttpLoggingInterceptor()
.apply { level = HttpLoggingInterceptor.Level.BODY }
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
return retrofit.create(GitHubApi::class.java)
}
}}
user model:
data class User(val userName: String)
MainActivity:
private fun createApiService() : GitHubApi{
val url = "https://api.github.com/"
val interceptor = HttpLoggingInterceptor()
.apply { level = HttpLoggingInterceptor.Level.BODY }
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
return retrofit.create(GitHubApi::class.java)
}
private fun loadData() {
val api = GitHubApi.getClient()
api.getUser("fabpot").enqueue(object : Callback<User> {
override fun onFailure(call: Call<User>, t: Throwable) {
t.printStackTrace()
}
override fun onResponse(
call: Call<User>,
response: Response<User>
) {
if (!response.isSuccessful) {
runOnUiThread { showErrorMessage(response.code().toString()) }
}
response.body()?.let { showErrorMessage(it.repoName) }
}
})
}
There is no key userName exist in github api.
try editing your data class this way.
data class User(val name: String)
Try removing the beginning slash "/" in your #GET method.

How to refresh token using okhttp authenticator with multiple request at a time

I am using retrofit for networking in my project. The problem is I have to call 2 requests from my first activity. It works fine but when the access token expires it has to refresh token. I have implemented a call using okhttp Authenticator. But it is calling multiple times and this error is showing too too many followup request 21
EDIT
I updated TokenAuthenticator class and added synchronized(). but it is returning from if (originalRequest.header("Authorization") != null) return null . I am following this answer https://stackoverflow.com/a/52513122/10243953
If i am removing if (originalRequest.header("Authorization") != null) return null this line then its working but in log report i see its calling for refresh token multiple times. How can i avoid this multiple time calls?
This is my Authenticator class
class TokenAuthenticator : Authenticator {
private val refreshTokenGrandType = "refresh_token"
private var oldToken: String? = null
private var newToken: String? = null
override fun authenticate(route: Route?, response: Response?): Request? {
oldToken = SharedPreferenceManager(MainApplication.applicationContext()).getToken()
if (response == null) return null
val originalRequest = response.request()
if (originalRequest.header("Authorization") != null) return null
if(!isTokenSaved()){
synchronized(this) {
RetrofitClient.client.create(Auth::class.java).refresh_token(
SharedPreferenceManager(MainApplication.applicationContext()).getRefreshToken()!!,
refreshTokenGrandType
).enqueue(object : Callback<Token> {
override fun onFailure(call: Call<Token>, t: Throwable) {
Toast.makeText(
MainApplication.applicationContext(),
t.message,
Toast.LENGTH_SHORT
).show()
Log.d("TokenAuth", t.message!!)
}
override fun onResponse(
call: Call<Token>,
response: retrofit2.Response<Token>
) {
if (response.isSuccessful) {
val body = response.body()
newToken = body!!.access_token
val refresh_token = body.refresh_token
SharedPreferenceManager(MainApplication.applicationContext()).accessToken(
newToken!!,
refresh_token
)
} else {
val error = response.errorBody()
Log.d("TokenAuthRes", error!!.string())
}
}
})
}
}
return originalRequest
.newBuilder()
.header(
"Authorization",
"Bearer ${SharedPreferenceManager(MainApplication.applicationContext()).getToken()}"
)
.build()
}
fun isTokenSaved() : Boolean{
if (newToken == null) return false
if (oldToken.equals(newToken)) return false
else return true
}
}
Retrofit client
object RetrofitClient {
private lateinit var interceptor : Interceptor
private lateinit var okHttpClient: OkHttpClient
private var retrofit : Retrofit? = null
val client : Retrofit
get(){
val context : Context = MainApplication.applicationContext()
interceptor = Interceptor { chain ->
val url = chain.request()
.url()
.newBuilder()
.build()
val request = chain.request()
.newBuilder()
.addHeader("Authorization","Bearer ${SharedPreferenceManager(context).getToken()}")
.url(url)
.build()
return#Interceptor chain.proceed(request)
}
okHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.addInterceptor(NoInternetInterception(context))
.authenticator(TokenAuthenticator())
.connectTimeout(1, TimeUnit.MINUTES)
.build()
if (retrofit == null){
retrofit = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(const.URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit!!
}
}

Categories

Resources