2012-04-02 76 views
30

使用碎片时,处理方向改变的正确方法是什么?碎片和方向改变

我有一个包含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} 

这是假定是我的活动试图重新附上它的方向改变之前,但该片段包含片段画像不存在的观点模式错误被抛出。

我试过以下隐藏/删除/分离方法,但仍然得到错误。告诉片段不再需要的正确方法是什么,并且不要尝试显示?

@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; 
    } 
} 
+0

同样的问题,但解决方案没有帮助我的情况出于某种原因。 http://stackoverflow.com/questions/6164341/handling-orientation-changes-with-fragments – Kuffs 2012-04-02 13:26:38

+0

此博客提供了处理方向更改的所有选项http://www.techrepublic.com/blog/android-app-builder/处理方向改变在android-ui-framework/ – 2013-07-28 11:35:11

+0

哎呀!没有检查日期。无论如何,我只将它连接起来,因为它显示了所有可用的选择,并真正帮助了我。如您所知,代码在这里和其他地方的解决方案中可用,因此提交了评论而不是解决方案。我不知道如何提供这些信息,我发现它非常有用。 – 2013-07-28 19:16:18

回答

-1

我想我解决了它。

我将片段添加到后退堆栈中,然后在活动关闭之前再次将其弹出,从而有效地将其删除。似乎工作到目前为止。

+0

似乎是一个不确定的解决方案。在活动关闭之前,您必须检查方向,并决定是否将其弹出,因为在活动重新启动时可能需要将其取出。 – AndroidDev 2015-07-24 20:32:24

+1

3年前。很久没有忘记。 – Kuffs 2015-07-25 21:18:16

-4

你不再需要这个活动了,因为片段将被显示在内。所以,你可以完成活动

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

我确实需要这项活动。如果它是我不需要的左侧片段,我只需要这个活动。这是我不想要的片段。 – Kuffs 2012-04-02 11:57:00

0

通常你有两个片段(左/右),一个主要活动和正确的片段(在手机设备上展示,只有当)一个容器活动。这是在这个博客条目描述:The Android 3.0 Fragments API

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); 
    } 
} 
+0

这是正确的,并且是我的应用程序的工作方式。问题是如何从双窗格切换到单窗格而不会发生错误。博客文章没有涵盖这种可能性(或者至少没有提及如何处理,而不会遇到我在我的问题中详述的错误) – Kuffs 2012-04-02 12:38:31

+0

如果您有两个不同的布局文件(res/layout-xlarge-land有一个片段和一个LinearLayout)和(res/layout只有左边的片段)。当从横向改变为纵向(你的问题)时,新的较小的布局将被提取,并且正确的片段自动消失。但是,您需要在纵向模式下为正确的片段提供容器活动。在使用上面提到的博客时,请熟悉ID标题,细节和android.R.id.content。这是一个有点棘手他们做什么... – 2012-04-02 13:08:40

+0

我已经有你提到的一切,并得到一个错误,因为包含我的第二个片段横向模式的FrameLayout不存在于我的肖像模式布局,因此我假设我需要以某种方式防止第二个片段自动重新加载。我可以通过包含一个隐藏的framelayout并允许片段重新实例化自己,但我不喜欢使用解决方法,而宁愿为此问题提供解决方案。 – Kuffs 2012-04-02 13:15:51

1

如果您保留片段,请不要保留它。

setRetainInstance(false) 

代替

setRetainInstance(true) 
13

我遇到了同样的问题,我想我找到了另一种解决方案。这种解决方案可能会更好,因为您不必将片段添加到后端堆栈。

删除您的活动中的右侧片段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

请小心使用此解决方案,因为提交不会立即发生。这会导致commit和super.onSaveInstanceState(state)之间的竞争条件。有时候,提交会在状态被保存后发生,这会引发异常。 – DroidT 2013-10-21 13:55:48

+0

@DroidT那么做到这一点的正确方法是什么? – theblang 2014-06-02 20:26:26

+2

@mattblang executePendingTransactions(); – 2014-09-09 10:24:54

0

如果你有一个左,右窗格和窗格(通常是右侧窗格)中的一个双窗格的活动是假设不显示在设备切换到肖像模式,让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; 
    } 
} 
-1

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 Developers blog