roomorama / Caldroid

A better calendar for Android
Other
1.42k stars 531 forks source link

Cannot be nested within a fragment #40

Closed ened closed 11 years ago

ened commented 11 years ago

Given I add the CaldroidFragment into an existing fragment, I will receive this error message:

java.lang.IllegalStateException: Can't retain fragements that are nested in other fragments

This is how I set things up:

@EFragment(R.layout.frg_analysis)
public class AnalysisFragment extends SherlockFragment {

    @AfterViews
    protected void setupView() {
        CaldroidFragment caldroidFragment = new CaldroidFragment();
        Bundle args = new Bundle();
        Calendar cal = Calendar.getInstance();
        args.putInt("month", cal.get(Calendar.MONTH) + 1);
        args.putInt("year", cal.get(Calendar.YEAR));
        caldroidFragment.setArguments(args);

        FragmentTransaction t = getChildFragmentManager().beginTransaction();
        t.add(R.id.containerCalendar, caldroidFragment);
        t.commit();
    }
}

Stackoverflow has some hints: http://stackoverflow.com/questions/14850573/cant-retain-nested-fragments .

Full stacktrace:

E/AndroidRuntime( 1763): java.lang.IllegalStateException: Can't retain fragements that are nested in other fragments
E/AndroidRuntime( 1763):    at android.support.v4.app.Fragment.setRetainInstance(Fragment.java:742)
E/AndroidRuntime( 1763):    at com.caldroid.CaldroidFragment.onCreate(CaldroidFragment.java:924)
E/AndroidRuntime( 1763):    at android.support.v4.app.Fragment.performCreate(Fragment.java:1437)
E/AndroidRuntime( 1763):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:877)
E/AndroidRuntime( 1763):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
E/AndroidRuntime( 1763):    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
E/AndroidRuntime( 1763):    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
E/AndroidRuntime( 1763):    at android.support.v4.app.Fragment.performStart(Fragment.java:1481)
E/AndroidRuntime( 1763):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:941)
E/AndroidRuntime( 1763):    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
E/AndroidRuntime( 1763):    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
E/AndroidRuntime( 1763):    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
E/AndroidRuntime( 1763):    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
E/AndroidRuntime( 1763):    at android.os.Handler.handleCallback(Handler.java:725)
E/AndroidRuntime( 1763):    at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime( 1763):    at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime( 1763):    at android.app.ActivityThread.main(ActivityThread.java:5041)
E/AndroidRuntime( 1763):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 1763):    at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime( 1763):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
E/AndroidRuntime( 1763):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
E/AndroidRuntime( 1763):    at dalvik.system.NativeStart.main(Native Method)
thomasdao commented 11 years ago

Did you try to set API level more than Android 4.2?

hackfrag commented 11 years ago

Nested fragments cannot have setRetainInstance(true) I removed this line in the CaldroidFragment and now it works :)

thomasdao commented 11 years ago

unfortunately if you remove that you cannot use it as dialog... The way Android handle the states quite messy :(

ened commented 11 years ago

Yes, it's on both 4.2, 4.3 and 2.3 (target API is always latest, min API is 10). Both with support library and without. We are using my fork now with the setRetainInstance call omitted (https://github.com/ened/Caldroid/tree/retain-instance).

@thomasdao I understand your point about the Dialog handling. Do you think the proposal from the SO link is helpful? Plus, starting from API 17 (and in recent support library) there is a method http://developer.android.com/reference/android/app/Fragment.html#getParentFragment(), which might be helpful to make the decision on whether to call setRetainInstance() or not?

thomasdao commented 11 years ago

@ened: can clarify a bit more on what you want to achieve? I haven't tried Roboguice so I don't understand your code fully.

In my app, I can include Caldroid within other Fragment as well. Only difference is I extend android.support.v4.app.Fragment and using SherlockFragmentActivity

Your suggestion is useful but I need time to test it out. Android is not always straightforward :(

ened commented 11 years ago

@thomasdao basically I'm using a fragment to present the UI to the user. The @AfterViews call is running just after onCreate is complete. Within the AnalysisFragment (inherits android.support.v4.app.Fragment now due to switch from ABS to ActionBarCompat) I'm simply adding the CaldroidFragment into the right place.

Maybe important: This is all done using the latest version of the compatibility library (r18).

thomasdao commented 11 years ago

Can you try below code:

FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction t = fragmentManager.beginTransaction();
t.add(R.id.containerCalendar, caldroidFragment);
t.commit();
ened commented 11 years ago

On a first try (running on 4.2), this works. Per http://developer.android.com/about/versions/android-4.2.html#NestedFragments I'm doing something that really should be done using the child fragment manager though.

thomasdao commented 11 years ago

I'll try to support getChildFragmentManger, but in the mean time you can use getSupportFragmentManager instead. To support both dialog and embedded fragments, sometimes I run into weird issues with states.

ened commented 11 years ago

Ok, thanks a lot for your help.

thomasdao commented 11 years ago

I found a simple way to fix this issue: just check if Caldroid is presented as dialog, and we only setRetainInstance(true) for dialog fragment. Pls let me know if it works for you :)

natanloterio commented 10 years ago

I had the same problem. change FragmentTransaction t = getChildFragmentManager().beginTransaction(); to FragmentTransaction t = getActivity().getSupportFragmentManager().beginTransaction();

ambassajy commented 10 years ago

hello everyone. i tried to embed caldroid in my app, but i still get some errors in my mainactivity. i'm using android 4.3 : here t.replace(R.id.calendar1, caldroidFragment); eclipse suggests me to change type of caldroidFragment from DialogFragment to Fragment. . and here FragmentTransaction t = getActivity().getSupportFragmentManager().beginTransaction(); getActivity() is showed as an error. any help will be appreciated

natanloterio commented 10 years ago

show your code, and also the error message plz

ambassajy commented 10 years ago

thx for the quick reply, but i managed to solve the problem. this is how i fixed it: android.support.v4.app.FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.replace(R.id.calendar1, caldroidFragment);

ambassajy commented 10 years ago

but i have another issue. as i embed caldroid in my app, pls can u show me how to implement on date click so that i can pop up a dialog box when i click on any date, and how to sync the calendar to my database so that a date background color change according to some data in my database. thx in advance.

thomasdao commented 10 years ago

These things are in the documentation https://github.com/roomorama/Caldroid#flexible-setup-can-be-embedded-or-shown-as-dialog, https://github.com/roomorama/Caldroid#custom-backgrounds-and-text-colors-for-different-dates and https://github.com/roomorama/Caldroid#display-user-events-on-caldroid

ambassajy commented 10 years ago

sorry to bother again , but i dont know how to implement it: this is what i tried: // Setup listener listener = new CaldroidListener() {

        @Override
        public void onSelectDate(final Date date, View view) {
            Toast.makeText(getApplicationContext(), formatter.format(date),
                    Toast.LENGTH_LONG).show();

view.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
    // TODO Auto-generated method stub
    Toast.makeText(getApplicationContext(), formatter.format(date),
            Toast.LENGTH_LONG).show();
}

}); }

thomasdao commented 10 years ago

Can you open new issue? It's quite hard to track. Btw to show dialog:

view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Create a dialog here
        CaldroidFragment dialogCaldroidFragment = CaldroidFragment.newInstance("Select a date", 3, 2013);

       // Add a listener as per documentation
       final CaldroidListener listener = new CaldroidListener() {

           @Override
            public void onSelectDate(Date date, View view) {
                // You can perform your method on selected date
            }
       };

        dialogCaldroidFragment.setCaldroidListener(listener);

        // show the dialog
        dialogCaldroidFragment.show(getSupportFragmentManager(),"TAG");
    }
});

Btw I think it will be good for you in long term to slow down and understand Android fundamental and do not rush, you can do much faster later