Bostone
Bostone

Reputation: 37154

Android - problems using FragmentActivity + Loader to update FragmentStatePagerAdapter

I'm trying to use FragmentActivity with ViewPager to display dynamic list of Fragments. There are plenty of examples on how to do a static version of it. My problem is that the list I display needs to be loaded dynamically and also can change based on user input (add/delete). I'm trying to use customized android.support.v4.content.Loader to load set of data that I can use to build my list.

Everything goes fine in my setup until I get to the point when I want to update the adapter and issue FragmentStatePagerAdapter#notifyDataSetChanged() call at which point this code is executed (from FragmentStatePagerAdapter)

public void finishUpdate(View container)
{
    if(mCurTransaction != null)
    {
        mCurTransaction.commit(); // BANG!!! The exception is thrown
        mCurTransaction = null;
        mFragmentManager.executePendingTransactions();
    }
}

The transaction commit fails with this message:

java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished

because within FragmentManagerImpl this code is executed:

private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }
}

It turns out that mNoTransactionsBecause value is not null and it is set in LoaderManagerImpl.LoaderInfo when the result is returned back to onLoadFinished

I was looking at the various variables trying to somehow change tramsaction.commit() to transaction.commitAllowingStateLoss() but everything related to transaction seems to be private or at least package-protected.

Can someone give me a general idea if I can do what I need to do (and how)?

Just to note that my code works fine if instead of using Loader I run the loading ops in AsyncTask

Upvotes: 16

Views: 12730

Answers (3)

Ibrahim Khalil
Ibrahim Khalil

Reputation: 41

It works using rootView.post(). Just define rootView variable in class scope and then inflate it onCreateView(). Finally onLoadFinished() simply use it like this:

            rootView.post(new Runnable() {
                public void run() {
                    General.showFragment();
                }

            });

Upvotes: 0

Ian Warwick
Ian Warwick

Reputation: 4784

I had a very similar problem to this and solved it by using a handler on the Fragment.

I wanted to show an alert dialog on onLoadFinished(), similar to the following

public class MyFragment extends Fragment 
    implements LoaderManager.LoaderCallbacks<T> {

    public void onLoadFinished(Loader<T> loader, T data) {
        showDialog();
    }

    public void showDialog() {
        MyAlertDialogFragment fragment = new MyAlertDialogFragment();
        fragment.show(getActivity().getSupportFragmentManager(), "dialog");

    }
}

But this gave an error

can not perform this action inside of onLoadFinished

The solution was to add a handler to the fragment to take care of showing the dialog

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if(msg.what == MSG_SHOW_DIALOG) {
            showDialog();
        }
    }
};

And then modify onLoadFinished(...) to send a message to the handler instead

   public void onLoadFinished(Loader<T> loader, T data) {
        handler.sendEmptyMessage(MSG_SHOW_DIALOG);
    }

Upvotes: 35

Nikolay Elenkov
Nikolay Elenkov

Reputation: 52956

You can copy FragmentStatePagerAdapter and change it however you like, or create your own PagerAdapter from scratch. Or simply don't use a Loader.

Upvotes: 0

Related Questions