32 votes

Fragments et changement d'orientation

Quelle est la manière correcte de gérer un changement d'orientation lors de l'utilisation de fragments ?

J'ai une mise en page de paysage qui contient 2 fragments (instanciés dans le code en FrameLayout s). Lorsque je passe en mode portrait (dont la mise en page ne contient qu'un seul FrameLayout qui ne contient que le volet de gauche), le fragment de droite n'est plus nécessaire.

Je reçois une erreur :

E/AndroidRuntime(4519): Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f060085 for fragment myFragment{418a2200 #2 id=0x7f060085}

Je suppose que mon activité essaie de rattacher le fragment à l'endroit où il se trouvait avant le changement d'orientation, mais comme la vue qui contient le fragment n'existe pas en mode portrait, une erreur se produit.

J'ai essayé les méthodes suivantes de masquage/suppression/détachement mais j'obtiens toujours l'erreur. Quelle est la manière correcte de dire à un fragment qu'il n'est plus nécessaire et de ne pas essayer de l'afficher ?

@Override
public void onCreate(Bundle b) {
    super.onCreate(b);
    Fragment f = getSupportFragmentManager().findFragmentById(R.id.fragholder2);

    //rightPane is a framelayout that holds my fragment.
    if (rightPane == null && f != null) {
         FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
         ft.hide(f);     // This doesnt work
         ft.remove(f);   // neither does this
         ft.detach(f);   // or this
         ft.commit;
    }
}

13voto

AUser Points 171

J'ai rencontré le même problème et je pense avoir trouvé une autre solution. Cette solution est peut-être meilleure parce que vous n'avez pas besoin d'ajouter le fragment à la pile arrière.

Retirez le fragment de droite de votre activité en Activity.onSaveInstanceState() antes de en appelant super.onSaveInstanceState() . Cela fonctionne pour moi :

public MyActivity extends Activity
{   
    @Override
    public onCreate(Bundle state)
    {
        super.onCreate(state);

        // Set content view
        setContentView(R.layout.my_activity);

        // Store whether this is a dual pane layout
        mDualPane = findViewById(R.id.rightFragHolder) != null;

        // Other stuff, populate the left fragment, etc.
        .
        .
        .
        if (mDualPane)
        {
            mRightFragment = new RightFragment();
            FragmentManager fm = getFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            ft.replace(R.id.rightFragHolder, mRightFragment);
            ft.commit()
        }
    }

    @Override
    public void onSaveInstanceState(Bundle state)
    {
        if (mDualPane)
        {
            FragmentManager fm = getFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            ft.remove(mRightFragment);
            ft.commit()
        }

        super.onSaveInstanceState(state);
    }

    private boolean mDualPane;
    private Fragment mRightFragment;
}

1voto

NPike Points 5187

Si vous retenez le fragment, essayez de ne pas le retenir.

setRetainInstance(false)

au lieu de

setRetainInstance(true)

0voto

Harald Wilhelm Points 2760

En général, vous aurez deux fragments (gauche/droite), une activité principale et une activité conteneur pour le fragment de droite (uniquement lorsqu'il est affiché sur les appareils téléphoniques). Ceci est décrit dans cet article de blog : L'API pour les fragments d'Android 3.0

public class MyActivity extends FragmentActivity
    implements MyListFragment.MyContextItemSelectedListener {

    @Override
    public void onCreate(final Bundle bundle) {
        super.onCreate(bundle);

        setContentView(R.layout.activity);
    }

    // Callback from ListFragment
    @Override
    public void myContextItemSelected(final int action, final long id) {
        if (action == R.id.men_show) {
            processShow(id);
        }
    }

    private void processShow(final long id) {
        if (Tools.isXlargeLand(getApplicationContext())) {
            Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.right);
            if (fragment == null ||
                    fragment instanceof MyEditFragment ||
                    (fragment instanceof MyShowFragment && ((MyShowFragment) fragment).getCurrentId() != id)) {
                fragment = new MyShowFragment(id);

                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.right, fragment);
                transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                transaction.commit();
            }
        } else {
            Intent intent = new Intent();
            intent.setClass(this, MyShowActivity.class);
            intent.putExtra("ID", id);
            startActivityForResult(intent, MyConstants.DLG_TABLE1SHOW);
        }
    }

    private static boolean isXlargeLand(final Context context) {
        Configuration configuration = context.getResources().getConfiguration();

        return (((configuration.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) &&
                        configuration.orientation == Configuration.ORIENTATION_LANDSCAPE);
    }
}

-1voto

Kuffs Points 12318

Je pense l'avoir résolu.

J'ai ajouté le fragment à la pile arrière, puis avant la fermeture de l'activité, je l'ai retiré, ce qui permet de s'en débarrasser efficacement. Cela semble fonctionner jusqu'à présent.

-4voto

207 Points 2385

Vous n'avez plus besoin de cette activité car le fragment sera montré en ligne. Vous pouvez donc terminer l'activité

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        // we are in landscape so you do not need this activity anymore
        finish();
        return;
    }

    if (savedInstanceState == null) {
         // plugin right pane fragment
         YourFragment frgm = new YourFragment();
         getSupportFragmentManager().beginTransaction()
                .add(..., frgm).commit();
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X