Search code examples
javaandroidandroid-fragmentsandroid-backgroundandroid-thread

Destroyed fragment content remains on screen


I have fragments making API call via Retrofit + RxJava. I subscribe the Subscription in onActivityCreated and dispose at onDestroy. When I switch from FragmentA to FragmentB while FragmentA is still processing the API call, FragmentB appears below the content of FragmentA. It means FragmentA contents remains on top of the screen and there is no control over it.

FragmentA.java

public class FragmentA extends Fragment {

    @BindView(R.id.swipe_refresh) SwipeRefreshLayout mSwipeRefresh;
    @BindView(R.id.recycler_view) RecyclerView mRecyclerView;

    private ItemsAdapter mAdapter;

    private CompositeDisposable mCompositeDisposable = new CompositeDisposable();

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_list, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        ButterKnife.bind(this, view);

        mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                fetchItems();
            }
        });

        mAdapter = new ItemsAdapter();

        mRecyclerView.setAdapter(mAdapter);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mSwipeRefresh.setRefreshing(true);
        fetchItems();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mCompositeDisposable.clear();
    }

    private void fetchItems() {
        RequestInterface requestInterface = Utils.createService();
        mCompositeDisposable.add(requestInterface.getItemsForA()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer<Response>() {
                @Override
                public void accept(@NonNull Response response) throws Exception {
                    mAdapter.swapItems(response.getItems());
                    mSwipeRefresh.setRefreshing(false);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(@NonNull Throwable throwable) throws Exception {
                    Toast.makeText(getActivity(), "Error: " + throwable.getLocalizedMessage(), Toast.LENGTH_LONG).show();
                    mSwipeRefresh.setRefreshing(false);
                }
            }));
    }
}

FragmentB.java

public class FragmentB extends Fragment {
    //Same as `FragmentA` but different API call
}

I have also did some logging and found out that all of the life-cycle methods for FragmentA including onDestroyView gets called.


Solution

  • You need to call following methods on SwipeRefreshLayout to fix this.

        swipeRefreshLayout.setRefreshing(false);
        swipeRefreshLayout.destroyDrawingCache();
        swipeRefreshLayout.clearAnimation();
        super.onDestroyView();
    }