Refreshing Fragment View while using FragmentStatePagerAdapter
Asked Answered
W

1

9

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.

Waggon answered 28/2, 2013 at 1:12 Comment(11)
in your setup, what does each fragment represent? Is it only one fragment showing on the screen at a time? Where is the code you added? Is it inside the fragment class? Finally, what is GridRow?Slider
Hi Sherif, each fragment represent a chess board. I have an activity which calls a container fragment, this containerFragment has a viewpager which has the FragmentStatePagerAadaper set. Each adapter item is a fragment and in this fragment in its onCreatView each chess view is initialised. Also the listener for a cell is in the same fragment where I check for current states and new state and change the state accordingly. A GridRow is just a row of checkedTextview representing a cell. I hope this answers all your questions, any hints....?Waggon
The fact that everything happens inside your fragment means that all this hassle is not needed. Are you sure your selector (background) is correct? Can you show it and your xml for each cell. Usually the case when the view is not updating happens when you're trying to update a specific fragment inside the viewpager.Slider
The selection functionality is same for all fragments (no specifics). And also I am not trying to update anything from the view pager, its all in the fragment. Sorry the NDA doesn't allow me to share code. In short, how can I update the view within the fragment listener. ThanksWaggon
Fragments in FragmentAdapters are generally self-contained - unless the Fragment changes its views on its own, you really can't do much about it without hacks like a WeakReference Map and findViewByTag. If you need to do it from the Activity and abhor the hacks, you need to establish your own way to do Activity -> Fragment communication that doesn't rely on the Activity being able to get a reference to the Fragment (e.g., broadcasts, event buses like Guava's - or Otto - or Ambassador, etc.). Personally, I choose the WeakReference Map - it's far simpler than the clean way.Pessa
Thanks @Pessa for the input, yes the Fragment changes its views on its own. Doing it from the Activity makes no sense here. Its just about refresh/update of the fragment view on changes made within the fragment.Waggon
Are you using some adapter-GridView combination in your code or GridRow is just some layout like LinearLayout, if it is a GridView then consider updating your data and calling myGridAdapter.notifyDataSetChanged(); but I guess you are not using GridView. In that case try calling GridRow.requestLayout(); If you are updating your Fragments GUI from Fragment's code then you shouldn't be needing all this, something else is wrong. Try making one pager, one cell fragment and share your code.Fick
I think it will be easy by just resetting/reinitializing the FragmentStatePagerAdapter. If it does not work then Please post your code so that I can serve you better...Charleycharlie
ok thanks guys let me check and will get back with the relevant code like @M-WaJeEh says. And yes I am not using GridView, its actually only LinearLayout, and GridRow is just a row of checkedTextview. And yes also that I am updating my fragment within Fragment's codeWaggon
Update: started work on rest of the app, haven't found a solution yet.Waggon
@Waggon did you ever found a solution for this? Can you post the correct answer?Ironhanded
M
0

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.

Mcconaghy answered 3/6, 2013 at 17:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.