addInterceptor intercept NullPointException. in Retrofit2 - android

I got this error:
Fatal Exception: kotlin.KotlinNullPointerException
com.example.manager.helper.my_api.MyServiceGenerator$createService$$inlined$-addInterceptor$1.intercept (Interceptor.kt:81)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.kt:100)
okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp (RealCall.kt:197)
okhttp3.internal.connection.RealCall$AsyncCall.run (RealCall.kt:502)
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1133)
java.lang.Thread.run (Thread.java:762)
And I have no idea why it caused.
What I implemented is:
val logging = HttpLoggingInterceptor()
if (BuildConfig.DEBUG) { // If Build is Debug Mode, Show Log
logging.level = HttpLoggingInterceptor.Level.BODY // Logs request and response lines and their respective headers and bodies (if present).
} else { // Otherwise, show nothing.
logging.level = HttpLoggingInterceptor.Level.NONE // No logs
}
val client = OkHttpClient.Builder()
client.addInterceptor {
val original = it.request()
val request = original.newBuilder()
.header("User-Agent", MyApp.httpUserAgent!!)
.build()
it.proceed(request)
}
client.addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)

You are not finished building of your client. That's why it's null. In general you forgot to call build() method.
That's how it have to be implemented.
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(30, TimeUnit.SECONDS)
.callTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()

If you're using !! in your codes you should use it with a null check. Like this
if(MyApp.httpUserAgent != null) {
val request = original.newBuilder()
.header("User-Agent", MyApp.httpUserAgent!!)
.build()
else {
//here do something in case of null
}

I have the same problem when upgrade logging-interceptor from 3.10.0 to 4.7.2
Debug find cause is ssl factory
// old code
builder.sslSocketFactory(sslSocketFactory)
change the code to new code
// new code
builder.sslSocketFactory(sslSocketFactory, x509TrustManager)

Related

RxAndroid + Retrofit callTimeout doesn't trigger onError

I am using RxAndroid + Retrofit to make http request. Code looks like below:
Interceptor headerInterceptor = getHeaderInterceptor();
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.callTimeout(5, TimeUnit.SECONDS)
.addInterceptor(headerInterceptor)
.addInterceptor(httpLoggingInterceptor)
.build();
Gson gson = new GsonBuilder()
.setLenient()
.create();
sRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
Use it like this:
ApiProvider.provideApi(MyApi.class)
.submit(id, mRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
Log.w("tag", "success");
},
throwable -> {
Log.w("tag", "error");
}
);
I set connectTimeout / readTimeout / writeTimeout to be 60 seconds, and set callTimeout to be 5 seconds.
I know this configuration may be not reasonable but I just want to get a timeout exception after 5 seconds, and the Log.w("tag", "error"); could be called.
However, I found this line will never be called for my testing. And if I set connectionTimeout to 1 second, then this line will be called immediately.
So what I should do if I want callTimeout to trigger the log error line?
As for as I can see, I think your problem maybe isn't from how many seconds you set for callTimeout(5, TimeUnit.SECONDS), I think your maybe Rx stream have already throw some errors, so stream just break you can get any response from here. However, you reset time seconds to 1s, and then you restart app, this time stream not break and you get error.
So simple re-test it again to make sure your stream won't break even before enter this subscribe.
And I have been test with some stupid implementations:
class MainActivity : AppCompatActivity() {
val delayInterceptor = object : Interceptor {
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
Thread.sleep(6000L)
return chain.proceed(chain.request())
}
}
val client: OkHttpClient = OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.callTimeout(5, TimeUnit.SECONDS)
.addInterceptor(delayInterceptor)
.build()
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("https://en.wikipedia.org/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
data class Wiki(
#SerializedName("type")
val type: String
)
interface WikiService {
#GET("api/rest_v1/page/random/summary")
fun getRandomSummary(): Single<Wiki>
}
#SuppressLint("CheckResult")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
retrofit.create(WikiService::class.java)
.getRandomSummary()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Log.d("tag", "success")
}, {
Log.e("tag", "error")
})
}
}
I finally find the the cause.
I was using com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory, which had been deprecated per its readme: https://github.com/JakeWharton/retrofit2-rxjava2-adapter
This is now DEPRECATED!
Retrofit 2.2 and newer have a first-party call adapter for RxJava 2: https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2
After switching to retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory, everything start working nicely.
And BTW for any guy who might be interested in what the differences are between them two? Attach the key info I found below:

Retrofit 2: Setting Timeouts With No Effect

i am using the following:
implementation "com.squareup.retrofit2:converter-gson:2.6.0"
fun getOkHTTPClient(time: Int, interceptor: Interceptor): OkHttpClient {
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.callTimeout(5, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
return client.build()
}
retrofit2.Retrofit.Builder()
.baseUrl("$url/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
If i change the timeouts to 10 seconds, 20, 50, 500 etc.... the effect is the same. the call timeout is not obeying these rules.
Am i missing something?
Note: i am using Asynchronous requests if it helps in debugging the case

java.net.SocketTimeoutException occurred after 1s~3s but my ok http timeout set 10s

My app is using Retrofit+okhttp.
Sometimes, it throw SocketTimeoutException just through
1s~3s after request but my okhttp timeout is setting 10s.
It's my code.
private static OkHttpClient getClient() {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.addInterceptor(headerinterceptor)
.build();
return client;
}
public static XXXX XXXX() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(XXXX)
.addConverterFactory(StatusProcessConverter.create(new GsonBuilder().setLenient().create()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(getClient())
.build();
XXXX methods = retrofit.create(XXXX.class);
return methods;
}
Can anyone help me ... why the sockettimeout occur less than 10s...

Okhttp3 set timeout is useless

OkHttpClient client;
client = new OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.build();
Request request22 = new Request.Builder()
.url("http://www.goo.com/")
.build();
Utils.myLog("-begin-");
Response response = null;
try {
response = client.newCall(request22).execute();
if (response.isSuccessful()) {
Utils.myLog("-donw-");
}
} catch (Exception e) {
e.printStackTrace();
Utils.myLog("-error-" + e.toString());
}
This is my code, I have set timeout to 5 seconds, but it still taked 20 seconds to receive "error unknownhostexception " after "begin"? why my code is useless? I have looked the source code of OKHTTP, default timeout is 10 seconds(if I'm right), I'm confused.
Anyone can help, id really appreciated.
For now, OkHttp can't interrupt time-consuming DNS requests (see https://github.com/square/okhttp/issues/95), but you still can do something like this:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.connectTimeout(15, TimeUnit.SECONDS)
.dns(hostname -> Single.fromCallable(
() -> Arrays.asList(InetAddress.getAllByName(hostname))
).timeout(15, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.onErrorReturnItem(new ArrayList<>())
.blockingGet())
.build();
Kotlin
class CustomDns : Dns {
override fun lookup(hostname: String): List<InetAddress> {
return Single.fromCallable {
InetAddress.getAllByName(hostname)
}.timeout(15, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.onErrorReturnItem(arrayOf())
.blockingGet().toList()
}
}
OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.dns(CustomDns())
.build()

HttpLoggingInterceptor not logging with retrofit 2

Im trying to log all the requests (with a network interceptor) using refrofit2, kotlin and logging-interceptor:
retrofit: "2.0.2"
okhttp3 : "3.2.0"
com.squareup.okhttp3:logging-interceptor 3.2.0
like:
val interceptor = HttpLoggingInterceptor()
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
val okHttpClient = OkHttpClient.Builder()
.addNetworkInterceptor(interceptor) // same for .addInterceptor(...)
.connectTimeout(30, TimeUnit.SECONDS) //Backend is really slow
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
sRestAdapter = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(if (host.endsWith("/")) host else "$host/")
.addConverterFactory(GsonConverterFactory.create(gson()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
It just print:
D/OkHttp: --> GET url...
D/OkHttp: --> END GET
What is happening?
--------------- EDIT --------
Errors doing requests on Main Thread are not showing by the logger, so be careful.
private val interceptor = run {
val httpLoggingInterceptor = HttpLoggingInterceptor()
httpLoggingInterceptor.apply {
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
}
}
private val okHttpClient = OkHttpClient.Builder()
.addNetworkInterceptor(interceptor) // same for .addInterceptor(...)
.connectTimeout(30, TimeUnit.SECONDS) //Backend is really slow
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
Instead of
val okHttpClient = OkHttpClient.Builder()
.addNetworkInterceptor(interceptor)
...
you should have something like:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(interceptor)
...
as the addNetworkInterceptor() plays with interceptors that observe a single network request and response, while addInterceptor() adds interceptor that observes the full span of each call: from the connection is established (if any) until after the response source is selected (either the origin server, cache, or both).
EDIT
Errors doing requests on Main Thread are not showing by the logger, so be careful
Doing networking on main thread is not an "ordinary" error. It will result in your app being killed by the system with NetworkOnMainThreadException and this will happen before interceptor would be given any chance to run.

Categories

Resources