i.ss i.ss - 3 years ago 160
Android Question

Why Injecting objects and making api calls in io() thread slows opening the Fragment?

In onAttach() of VacationFragment I'm calling featuredDays() from VacationViewModel -> VacationRepository ,
what I notice when I'm clicking on view which navigates to VacationFragment, it opens with delays , I'm waiting for several millisecond till it opens the VacationFragment.
and when I'm commenting vacationViewModel.featureDays(startDate,endDate)
it opens the Fragment without delay

class MainApplication : Application(), HasActivityInjector, HasSupportFragmentInjector {
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.builder().androidModule(AndroidModule(this)).build()
appComponent.inject(this)
}

class VacationFragment : Fragment() {

override fun onAttach(context: Context?) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
vacationViewModel = ViewModelProviders.of(activity, icaViewModelFactory).get(VacationViewModel::class.java)
vacationViewModel.featureDays(startDate,endDate)}
}

class VacationViewModel : ViewModel(), AppComponent.Injectable {

private val disposables: CompositeDisposable = CompositeDisposable()

@Inject
lateinit var vacationRepository: VacationRepository
val featuredFeaturedCalendar: MediatorLiveData<FeaturedCalendar> = MediatorLiveData()

fun featureDays(from: String, till: String) {

val disposable = vacationRepository
.featuredCalendar(from, till, KEY, ID)
.map { featuredCalendar ->
val holidays = arrayListOf<FeaturedCalendar.Holiday>()
featuredCalendar.holidays.forEach { holidayItem ->
val holiday = FeaturedCalendar.Holiday(format.parse(holidayItem.date), holidayItem.holiday)
holidays.add(holiday)
}
FeaturedCalendar(featuredCalendar.status, holidays)
}
.subscribeOn(Schedulers.io())
.observeOn(mainThread())
.subscribe(
{
featuredFeaturedCalendar.postValue(it)
},
{
throw IllegalStateException(it)
})

disposables.add(disposable)
}}


class VacationRepository(private val apiDaysSeResource: ApiDaysSeResource) {

fun featuredCalendar(from: String, till: String, key: String, id: String): Flowable<FeaturedCalendar> {
return apiDaysSeResource.days(from, till, key, id)//.toFlowable()
}


}

public interface ApiDaysSeResource {
Flowable<FeaturedCalendar> days(@Query("fran") String fran, @Query("till") String till, @Query("key") String key, @Query("id") String id);
}

Answer Source

For anyone who won't be reading the full chat/comments section from the OP - the issue was with the ApiDaysSeResource class, its creation takes a lot of time to finish. As injections happen synchronously in onAttach(), the slowdown is therefore evident at startup. From the tests OP did, it seems that the slowdown was 1.0 - 1.5 seconds, which is a lot.

If you have some spare time, I wrote a lengthy post about this issue and how to asynchronously inject singletons when you don't have access to the constructor that takes a long time time to finish. Click here to read the article.

The basic idea is to inject an Observable<YourSlowThing> instead of YourSlowThing - that would allow you to wait for the instance to become available, but still get the non-null dependency at startup.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download