2012-04-02 79 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