Подтвердить что ты не робот

Изменение фрагментов и ориентации

Каков правильный способ обработки изменения ориентации при использовании фрагментов?

У меня есть ландшафтный макет, содержащий 2 фрагмента (созданный в коде FrameLayout s). Когда я переключаюсь в портретный режим (макет которого содержит только один FrameLayout, который содержит только левую панель), фрагмент правой руки больше не требуется.

Я получаю сообщение об ошибке:

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

который предположил, что моя деятельность пытается повторно присоединить фрагмент, где он был до изменения ориентации, но поскольку представление, содержащее фрагмент, не существует в портретном режиме, возникает ошибка.

Я пробовал следующие методы hide/remove/detach, но все равно получаю ошибку. Каков правильный способ рассказать фрагмент, он больше не нужен и не пытается отображать?

@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;
    }
}
4b9b3361

Ответ 1

Думаю, я решил.

Я добавил фрагмент в задний стек, а затем до закрытия активности снова выскочил, что фактически избавилось от него. Кажется, работает до сих пор.

Ответ 2

Я столкнулся с той же проблемой, и я думаю, что понял другое решение. Это решение может быть лучше, потому что вам не нужно добавлять фрагмент в задний стек.

Удалите фрагмент правой стороны из вашей активности в Activity.onSaveInstanceState() до, вызвав super.onSaveInstanceState(). Это работает для меня:

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;
}

Ответ 3

Если вы сохраняете фрагмент, не пытайтесь его сохранить.

setRetainInstance(false)

вместо

setRetainInstance(true)

Ответ 4

Обычно у вас будет два фрагмента (слева/справа), один основной вид активности и один вид действия контейнера для правого фрагмента (только при отображении на телефонных устройствах). Это описано в этой записи в блоге: API флагов 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);
    }
}

Ответ 5

Если у вас есть действие с двумя панелями с левой и правой панелью, и одна из панелей (как правило, правая панель), как предполагается, не будет отображаться, когда устройство переключится в портретный режим, пусть Android сделает свое дело и воссоздает правильную панель, Но во время onCreateView правой панели первое, что вам нужно сделать, это проверить, доступен ли один из элементов макета, используемых панелью. Если это не так, удалите фрагмент с помощью FragmentManager и немедленно верните его:

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
    View myView = getActivity().findViewById(R.id.myView);

    if (myView == null)
    {
      FragmentTransaction fragTransaction = getFragmentManager().beginTransaction();
      fragTransaction.remove(this);
      fragTransaction.commit();
      return null;
    }
 }

Ответ 6

Android восстанавливает оба фрагмента во время вращения экрана. Но если вы добавите чек ниже в onCreateView(), это не даст вам проблем:

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        if (container == null) {
            // Currently in a layout without a container, so no
            // reason to create our view.
            return null;
        }

        // inflate view and do other stuff
    }

Я взял это из блог разработчиков Android.

Ответ 7

Вам больше не нужна эта активность, потому что фрагмент будет показан в строке. Таким образом, вы можете завершить работу

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();
    }
}