Amit Tiwari Amit Tiwari - 3 months ago 28
Android Question

Fire RxJava event change only when Fragment is visible in ViewPager

I have an

EditText
in an
Activity
where users can type and search for things. Below the search bar, I have 2
tabs
attached to a
ViewPager
. I have added a RxJava event change listener for the
EditText
in the 2
Fragments
that I have for the tabs. Here is the relevant code:

private Subscription subscription;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_people_search, container, false);
ButterKnife.bind(this, view);
LogUtil.i(TAG, "onCreateView called");

if (getActivity() != null) {
inputSearch = (EditText) getActivity().findViewById(R.id.editText11);
}

return view;
}

@Override
public void onResumeFragment() {
LogUtil.i(TAG, "onResumeFragment called");
if (subscription == null) {
doSearch();
}
}

private void doSearch() {
LogUtil.i(TAG, "doSearch called");
subscription = RxTextView.textChangeEvents(inputSearch)
.debounce(400, TimeUnit.MILLISECONDS)
.map(new Func1<TextViewTextChangeEvent, String>() {
@Override
public String call(TextViewTextChangeEvent textViewTextChangeEvent) {
return textViewTextChangeEvent.text().toString().trim();
}
})
.switchMap(new Func1<String, Observable<SearchUserData>>() {
@Override
public Observable<SearchUserData> call(String s) {
term = s;
if (previousTerm.equalsIgnoreCase(term) && TextUtils.isEmpty(term)) {
//do not reset pagination variables
} else if (!previousTerm.equalsIgnoreCase(term) && TextUtils.isEmpty(term)) {
min = 0;
max = 14;
} else if (previousTerm.equalsIgnoreCase(term) && !TextUtils.isEmpty(term)) {
//do not reset pagination variables
} else {
min = 0;
max = 14;
}
loadMoreOrNot = true;
previousTerm = term;
DiscoverAPI discoverAPI = restAdapter.create(DiscoverAPI.class);
return discoverAPI.getRxPeopleSearchResult(min, max, s, "user");
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getRxSearchObserver());
}


What I want is, when I search something, the query should go to the backend only for the tab which is selected right now, not for both the tabs. How can I do this?

Answer

I think there is two options.

Use filter:

    subscription = RxTextView.textChangeEvents(inputSearch)
            .debounce(400, TimeUnit.MILLISECONDS)
            .filter(textViewTextChangeEvent -> getUserVisibleHint())
            .map(..)
            ...

Or subscribe / unsubscribe when setUserVisibleHint is called (As commented by @Amir):

    @Override
    public void onResumeFragment() {
        //don't subscribe here
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (subscription != null) {
            subscription.unsubscribe();
            subscription = null;
        }
        if (isVisibleToUser) {
            doSearch();
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        if (subscription != null) {
            subscription.unsubscribe();
            subscription = null;
        }
    }