Search code examples
androidandroid-fragmentsandroid-viewpagerandroid-dialogfragment

Refreshing a fragment from a DialogFragment


I've been going around in circles trying to do something that seems pretty basic. I have a DialogFragment that accepts a users input, then, on submission, refreshes a ListView in a Fragment that is part of a ViewPager.

I have everything working except the Fragment with the ListView does not refresh itself. It's a little confusing though, because it does refresh the data, but I have to swipe a couple views, then back again to see the updated data.

After doing some research, I'm supposed to use getItemPosition and notifyDataSetChanged on the ViewPager and it should work. The problem is that calling notifyDataSetChanged results in a Recursive entry to executePendingTransactions exception being thrown:

Main Activity

public class Main extends SherlockFragmentActivity implements MyListFragment.OnRefreshAdapterListener, DialogConfirmation.OnRefreshKeywordsListener //Updated Code
{
    private static List<Fragment> fragments;

    @Override
    public void onCreate(final Bundle icicle)
    {    
        setContentView(R.layout.main);
    }

    @Override
    public void onResume()
    { 
        mViewPager = (ViewPager)findViewById(R.id.viewpager);

        fragments = new ArrayList<Fragment>();

        fragments.add(new MyListFragment()); //fragment with the ListView

        fragments.add(MyDetailFragment.newInstance(0));
        fragments.add(MyDetailFragment.newInstance(1));
        fragments.add(MyDetailFragment.newInstance(2));

        mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(mMyFragmentPagerAdapter);
    }

    private static class MyFragmentPagerAdapter extends FragmentStatePagerAdapter  {  

        public MyFragmentPagerAdapter(FragmentManager fm) {  
             super(fm);  
        }  

        @Override  
        public Fragment getItem(int index) {
            return fragments.get(index);
        }  

        @Override
        public int getCount() {  
             return 4;  
        }

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

    @Override
    public void onRefreshAdapterListener() {
        this.mMyFragmentPagerAdapter.notifyDataSetChanged();
    }

    //Updated Code
    @Override
    public void onRefreshTextListener() {
        MyListFragment tf = (MyListFragment)getSupportFragmentManager().findFragmentById(R.id.fragmentText);

        if (tf == null)
            tf = (MyListFragment)this.fragments.get(0);

            tf.RefreshText();       
    }
}

ListFragment

public class MyListFragment extends SherlockListFragment
{
    OnRefreshAdapterListener mRefreshAdapter;

    @Override
    public void onActivityCreated(Bundle savedState) {

        adapter = new CustomAdapter();

        /*code to add items to adapter */

        this.setListAdapter(adapter);

        adapter.notifyDataSetChanged();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        if (getArguments() != null && getArguments().getString("text").length() > 0)
        {
            SaveText(getArguments().getString("text"));
            this.mRefreshAdapter.onRefreshAdapterListener(); //this line causes a "java.lang.IllegalStateException: Recursive entry to executePendingTransactions" exception
        }

        return inflater.inflate(R.layout.listing, container, false);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        mRefreshAdapter = (OnRefreshAdapterListener)activity;
    }

    public interface OnRefreshAdapterListener {
        public void onRefreshAdapterListener();
    }


    @Override
    public void onDialogTextAdd(final String text) {
    }   
}

DialogFragment

public class DialogTextAdd extends DialogFragment implements OnEditorActionListener {

    private EditText mText;
    OnRefreshTextListener mTextKeywords; //Updated Code

    public interface DialogTextAddListener {
        void onDialogTextAdd(final String inputText);
    }

    public DialogTextAdd() {
        // Empty constructor required for DialogFragment
    }

    //Updated Code
    @Override
    public void onAttach(Activity act) {
        super.onAttach(act);
        mTextKeywords = (OnRefreshTextListener)act;
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.dialog_edit, container);
        mText = (EditText)view.findViewById(R.id.text_add);
        getDialog().setTitle("Add Text");

        // Show soft keyboard automatically
        mText.requestFocus();
        getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
        mText.setOnEditorActionListener(this);

        return view;
    }

    @Override
    public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
        if (EditorInfo.IME_ACTION_DONE == actionId) {

            MyListFragment mf = new MyListFragment();
            Bundle args = new Bundle();
            args.putString("text", mText.getText().toString());
            mf.setArguments(args);

            //this seems to be intefering with the notifyDataSetChanged in the listing fragment
            getActivity().getSupportFragmentManager().beginTransaction().add(mf, "my_fragment").commit();

            mTextKeywords.onRefreshTextListener(); //Updated Code

            this.dismiss();
            return true;
        }
        return false;
    }
}

Solution

  • I have everything working except the Fragment with the ListView does not refresh itself.

    There is no point on creating and adding to the FragmentActivity a new instance of MyListFragment. From your code it appears that you store the fragments that you use in a list so you have references to them(also, just out of curiosity, did you setup the fragments in portrait, did a rotation of the phone and retried to use the DialogFragment?). Having references to those fragment means you could always get them from the list and use them to call a refresh/update method.