linhbeopr0 linhbeopr0 - 2 months ago 14
Android Question

Fragment still displayed on screen when back key while refreshing with SwipeRefreshLayout

I have an activity with 2 fragments: A and B. currently A was added on activity. After click a button:

ft.replace(containerId, B, tag);
ft.addToBackStack("A");
ft.commit();


B was displayed and A was removed normally.
Pull to refresh and press back while the progress is loading:

// this is implementation in OnBackPressed()
....
int backStackEntryCount = fm.getBackStackEntryCount();
if (backStackEntryCount > 0) {
fm.popBackStackImmediate();
}
....


The problem is fragment B still displayed on screen (blank) and overlap fragment A, if back again app will exit. Some information about B:


  • I implemented SwipeRefreshLayout on B

  • Here is B source code:

    public class B extends MyFragment {

    protected View view;
    protected ListView listView;
    protected ImageView progress;
    protected TextView notifText;
    protected LayoutInflater inflater;
    protected PTRBaseAdapter adapter;
    protected SwipeRefreshLayout mSwipeRefreshLayout;

    protected String emptyText;
    protected boolean fromRest;
    protected int loads = 0;
    protected float mPreviousX = 0;
    protected float mPreviousY = 0;

    protected void doRefresh(boolean fromRest) {
    if (!isAdded()) return;
    notifText.setVisibility(View.GONE);
    fetchFromDatabase();
    if (fromRest) {
    refresh();
    }
    }

    private void fetchFromDatabase() {
    /* fetch data from db here and got the "list" */
    adapter = new EventAdapter(list);
    listView.setAdapter(adapter);
    loads++;
    if (adapter.getCount() == 0) {
    notifText.setText(R.string.NoEvents);
    notifText.setVisibility(View.VISIBLE);
    } else {
    notifText.setVisibility(View.GONE);
    }
    }

    private void refresh() {
    if (!isAdded()) return;
    GenericManager.getInstance().fetchEvents(mContext, new OnFinished() {
    @Override
    public void onFinished(boolean result) {
    if (result) {
    if (isAdded() && getActivity() != null) {
    fetchFromDatabase();
    adapter.notifyDataSetChanged();
    listView.invalidate();
    mSwipeRefreshLayout.setRefreshing(false);
    }
    }
    }
    });
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.ptr_list, container, false);
    this.inflater = inflater;
    mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeRefresh);
    mSwipeRefreshLayout.setColorSchemeResources(R.color.md_material_blue_600);

    listView = (ListView) view.findViewById(R.id.pull_refresh_list);
    listView.setOnItemClickListener(mOnItemClickListener);
    listView.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    boolean enable = false;
    if (listView != null && listView.getChildCount() > 0) {
    boolean firstItemVisible = (listView.getFirstVisiblePosition() == 0);
    boolean topOfFirstItemVisible = (listView.getChildAt(0).getTop() == 0);
    enable = firstItemVisible && topOfFirstItemVisible;
    }
    mSwipeRefreshLayout.setEnabled(enable);
    }
    });

    mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
    public void onRefresh() {
    refresh();
    }
    });

    progress = (ImageView) view.findViewById(R.id.progress);
    progress.setVisibility(View.GONE);

    notifText = (TextView) view.findViewById(R.id.notifText);
    notifText.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {

    int action = event.getActionMasked();
    float x = event.getX();
    float y = event.getY();

    switch (action) {
    case MotionEvent.ACTION_DOWN:
    break;
    case MotionEvent.ACTION_MOVE:
    float dx = x - mPreviousX;
    float dy = y - mPreviousY;

    if (dy > 300) {
    mSwipeRefreshLayout.post(new Runnable() {
    @Override
    public void run() {
    mSwipeRefreshLayout.setRefreshing(true);
    doRefresh(fromRest);
    }
    });
    }
    break;
    case MotionEvent.ACTION_UP:
    break;
    }
    mPreviousX = x;
    mPreviousY = y;
    return true;
    }
    });

    setTopbarTitle();
    return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    doRefresh(true);
    }

    @Override
    public void setTopbarTitle() {
    topbar = (TopBar) getActivity().findViewById(R.id.topbar);
    topbarTitle = R.string.Events;
    ((PlandayActivity) getActivity()).setTabBarVisibility(false);
    topbar.setVisibility(View.VISIBLE);
    super.setTopbarTitle();
    }

    @Override
    public void onResume() {
    doRefresh(false);
    super.onResume();
    }

    /* The adapter for list but I think it does not affect anything */



And in MyFragment I have override onDettach:

@Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);

} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}


Layout of fragment B:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PlandayActivity">

<RelativeLayout
style="@style/viewstyle">

<com.planday.ninetofiveapp.viewcomp.TopBar
android:id="@+id/topbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />

<ImageView
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/progress" />

<ListView
android:id="@+id/pull_refresh_list"
style="@style/ptr_style"
android:background="@color/white"
android:divider="@color/white"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/topbar" />

<TextView
android:id="@+id/notifText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/progress"
android:layout_centerInParent="true"
android:gravity="center"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:visibility="gone" />
</RelativeLayout>

</android.support.v4.widget.SwipeRefreshLayout>


I dont know why the fragment B went to onDetach but it still freezed on screen, I can see a little bit of A fragment at the bottom. Any suggestion is really really appreciated, I stucked at this thing about few days :(

I think the problem is in the implementation of B fragment but I cant figure it out, not sure the problem is from SwipeRefreshLayout or not ...

Answer

I solved problem myself with

mSwipeRefreshLayout.destroyDrawingCache();