Refreshing Fragment View while using FragmentStatePagerAdapter

AliR picture AliR · Feb 28, 2013 · Viewed 7.5k times · Source

Seems the refresh issue is discussed before, but none of the solutions worked for me.

What I am trying to do: I am using FragmentStatePagerAdapter. Each position of the adapter holds a fragment that has a linear layout that has chess like appearance, with each cell represented by a CheckedTextView.

And a listener that should listens for clicks and removes the previous selection on the cells and makes the new selection.

Whats working: Each fragment is loaded correctly with all the data/default states (calculated while the fragment is loaded in a list)

When I click a cell all the states from the saved cells list are fetched correctly and I can change see the state change in the code while debugging. At the same time I assign a new state for the CheckedTextView which represent a cell. This is set like:

CheckedTextView cellView = (CheckedTextView) GridRow.getChildAt(c);
                                cellView.setSelected(false);
                                cellView.setChecked(false);
                                cellView.setTag(cellsChess.get(i).get(c));

The Issue: Even though the values are stored and assigned correctly the view can't be refreshed the values of the cells in the view do not get updated.

Tips I have Tried that didn't worked: 1. Call adapter.notifyDataSetChanged: Can be called while using FragmentStatePagerAdapter only when we have overridden:

@Override
    public int getItemPosition(Object object){
        return POSITION_NONE;
    }

2. Adding Overriden methods for DestroyItem and also adding the fragments to a Map on getItem:

This is not appropriate as I am working with FragmentStatePagerAdapter, so the whole purpose of using this pagerAdapter would be gone.

3. Calling invalidate: This is inappropriate for this scenario, I need realtime refresh.

4. setTag() method in instantiateItem(): I don't think this is appropriate in this situation.

Referenced threads: Refresh images on FragmentStatePagerAdapter on resuming activity

ViewPager PagerAdapter not updating the View

Update ViewPager dynamically?

notifyDataSetChanged fails to update ListView

I have tried to state my issue as clear as possible, if anyone needs more clarification, do ask.

Urgent replies will be highly appreciated,

Cheers

****Update*****

I am using the ViewPagerIndicator, instead of the default ViewPager.

Answer

gm2008 picture gm2008 · Jun 3, 2013

In relation to notifyDataSetChanged() function, I have two different experiences.

When I used my subclass of ArrayAdapter to update a ListView, it worked straight. When I called notifyDataSetChanged(), the ListView items are updated.

However, when I used a subclass of FragmentStatePagerAdapter to update a ViewPager, calling notifyDataSetChanged() did not work. NotifyDataSetChanged() is responsible for calling the onChanged() function of all registered DataSetObserver, but the observers have not been registered automatically like in ArrayAdapter. You have to do the ground work by yourself.

To my surprise, DataSetObserver is not a interface but an abstract class. So I could not simply implement it in my subclass of fragment. I have to define a subclass of DataSetObserver, then define a member field in this class as a reference to my fragment, and in the overriden onChanged() function update your View display. The code is as follows:

public class DetailFragDataSetObserver extends DataSetObserver {
private DetailTextFragment view_instance;
protected static ArrayList<DetailFragDataSetObserver> list = new ArrayList<DetailFragDataSetObserver>();

public DetailFragDataSetObserver(DetailTextFragment f){
    view_instance = f;
    list.add(this);
}
public DetailTextFragment getView(){
    return view_instance;
}
public static DataSetObserver findDataSetObserverFor(DetailTextFragment f){
    for ( int i = 0; i<list.size(); i++){
        if ( list.get(i).getView() == f)
            return list.get(i);
    }
    return null;
}
public static void release(DataSetObserver observer){
    list.remove(observer);
    ((DetailFragDataSetObserver)observer).view_instance = null;
}
@Override
public void onChanged(){
    assert null != view_instance;

    view_instance.vUpdateData();
}
}

You have to be careful. You need to remember to nullify the reference and unregister the DataSetObserver object in your overriden fragment.onDestroy(), otherwise the fragment cannot be garbage collected.

Later, through looking into the source codes, I found ArrayAdapter and FragmentStatePagerAdapter and are not siblings. They are totally different. They are actually from different packages:

  android.widget.ArrayAdapter
  android.support.v4.app.FragmentStatePagerAdapter

That's why the former worked easily while the latter does not.