Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blocking UI thread on first initialization #3543

Open
ArcherEmiya05 opened this issue Apr 14, 2021 · 3 comments
Open

Blocking UI thread on first initialization #3543

ArcherEmiya05 opened this issue Apr 14, 2021 · 3 comments

Comments

@ArcherEmiya05
Copy link

ArcherEmiya05 commented Apr 14, 2021

I am getting a lot of hiccups Choreographer: Skipped 59 frames! The application may be doing too much work on its main thread. during first initialization of Retrofit which is noticeable when switching between fragments using navigation drawer. It will be fixed if I add delay on making request but I want to know if there is any neat solution on this? I tried to use Kotshi as it was stated on the other issue that it performs well than Moshi but no luck.

Home Fragment extending Parent Fragment

disposable = initRetrofit.getAssetItems(
            Singleton.assetField,
            limit
        )
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                { result ->

                    swipeRefreshLayout.isRefreshing = false

                    swipeRefreshLayout.isEnabled = false // Swipe gesture no longer needed

                    adapter.submitList(result.data)

                    logTxt.text = null

                },
                { error ->
                    Log.wtf("WTF", "${error.message}")
                    swipeRefreshLayout.isRefreshing = false
                    if (adapter.currentList.isEmpty() || (error is HttpException && error.code() == HttpURLConnection.HTTP_GATEWAY_TIMEOUT)){
                        adapter.submitList(mutableListOf()) // Pass an empty list if no cache
                        logTxt.setText(R.string.swipe_to_refresh)
                    }
                }
            )

Parent Fragment

protected val initRetrofit by lazy {
        EndpointServices.create(url, requireContext())
    }

EndpointServices class with companion object function create(string,context)

val httpClient = OkHttpClient.Builder()
                .cache(cache)
                .addInterceptor(interceptor)
                .callTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                .addNetworkInterceptor(interceptor())
                .addInterceptor(onlineOfflineHandling())
                .build()

            val retrofit = Retrofit.Builder()
                .addCallAdapterFactory(
                    RxJava2CallAdapterFactory.create()
                )
                .addConverterFactory(
                    MoshiConverterFactory.create()
                )
                .client(httpClient)
                .baseUrl(baseUrl)
                .build()
@JakeWharton
Copy link
Member

Do you have a systrace or profile screenshot which shows what's specifically to blame? I'm not sure what action we can take from this report.

A lot of things have to happen on first use of Retrofit: classloading Retrofit, OkHttp, and Okio; initialization of OkHttp's thread pools; initialization of adapters and converters and classloading+initialization of their backing libraries; and parsing of the service interface annotations. It might simply be death by a thousand cuts, but without a reproducing sample application we can run or some kind of trace/profiler output I don't know that we can really offer anything.

@ruieduardosoares
Copy link

@ArcherEmiya05 as @JakeWharton said, a lot of computation is going on, also i would recommend initializing such heavy objects on application startup using Hilt as a dependency injection mechanism for example.

@Ryubal
Copy link

Ryubal commented Jan 26, 2022

I can confirm this issue is still reproducible. To reproduce it's very simple, just create a MoshiConverterFactory with KotlinJsonAdapterFactory, and pass that to Retrofit. The very first call to enqueue will block the UI thread for a few ms. Retrofit instance is created way before the enqueue call, so this has nothing to do with the creation of the Retrofit instance. As soon as I change the converter to Gson, issue goes away (which is not a solution, since I need Moshi to serialize some objects later on)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants