2014-07-13 53 views
1

我有垃圾回收問題(我認爲)。 讓我解釋一下:碎片和垃圾收集器

這是我活動的簡化版本:

public Fragment fragA; 
public Fragment fragB; 

private FragmentManager manager = getSupportFragmentManager(); 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity); 

    if (savedInstanceState == null) { 
     fragA = new FragA(); 

     FragmentTransaction transaction = manager.beginTransaction();  
     transaction.add(R.id.container, fragA); 
     transaction.commit();   
    } 
} 

//A USER CLICK ON A BUTTON (in fragment A) TO SHOW FRAGMENT B: 
public void showFragB() { 
     fragB = new FragB(); 

     FragmentTransaction transaction = manager.beginTransaction();  
     transaction.replace(R.id.container, fragA); 
     transaction.commit(); 
} 

//A USER CLICK ON A BUTTON (in fragment B) TO DO SOME ACTIONS THAT REQUIRE fragA: 
public void doSomethingWithFragA() { 
     if (fragA == null) 
      Log.d("TAG", "WTF HAPPENS!?" 
     else 
      Log.d("TAG", "great, we can do the action" 
} 

現在,大部分的時間這個東西工作正常。 問題是...如果我打開應用程序,按下按鈕(在片段A)顯示片段B,按家庭按鈕(並做一些需要像瀏覽或看到youtube視頻ram),返回到我的應用程序,按其他按鈕(在片段B中)... fragA IS null!

但是該應用程序並沒有完全重新創建,因爲當我回到它時,片段B是可見的,就像應用程序永遠不會關閉它本身。

所以......你能解釋我這種行爲以及如何解決它嗎?

非常感謝!

+3

我不知道這個問題是你的代碼是什麼,但我懷疑* *它是垃圾收集器。 –

+0

爲什麼'fragA'指向一個對象?在你當前的代碼/僞代碼中,只有當'savedInstanceState'爲空(如果正在重新創建活動時情況不是這樣的話),纔在'onCreate()'方法中初始化fragA。 – Luksprog

+0

如果對象太早被銷燬,則沒有理由將該值賦給null。 null本身就是一種價值而不是缺乏價值。 –

回答

1

但該應用程序並沒有完全重新創建,因爲當我回到它時, 片段B是可見的,就像應用程序永遠不會自行關閉一樣。

這是錯誤的。有可能您的應用程序已完全重新創建,但系統將重新加載fragB,因爲它是在按下主頁按鈕(本例中爲R.id.container)時附加到容器的。

在描述的場景中savedInstanceState不爲空,所以你的代碼不會創建fragA。重要的是要注意,只有附加的片段會自動重新創建,但您使用替換刪除了fragA,因此它不會由系統重新創建。 (更換分離附着於容器每一個片段,之後附加新的片段。)

有這個問題的幾種解決方案,但我認爲最優雅的是設置fragA作爲目標片段:

public void showFragB() { 
    fragB = new FragB(); 

    // this line will force the system to recreate fragA, 
    // if fragB is recreated; 
    fragB.setTargetFragment(fragA, 0); 

    FragmentTransaction transaction = manager.beginTransaction(); 

    // I assumed fragA here is just a typo (it should be fragB)  
    transaction.replace(R.id.container, fragA); 
    transaction.commit(); 
} 

然後,您可以使用getTargetFragment中的fragB來獲得對fragA的參考。

重要:

你意識到fragA爲空,但實際上fragB爲空太,你只是從來沒有在代碼中使用該引用。

原因是系統只是爲您重新創建片段,但官方認爲這不會使您的fragAfragB等參考指向實際重新創建的片段(如果該片段是可見的話)。您必須手動做到這一點:

if (savedInstanceState == null) { 
    fragA = new FragA(); 

    FragmentTransaction transaction = manager.beginTransaction();  
    transaction.add(R.id.container, fragA, "TAG_TO_FIND_FRAG_A"); 
    transaction.commit();   
} 
else{ 
    fragA = manager.findFragmentByTag("TAG_TO_FIND_FRAG_A"); 

    if(fragA == null){ 
     // fragA was not attached so the system have not reacreted it 
    } else { 
     // fragA was attached! 
    } 
} 

注:

  • fragB的參考應該設置就像我上面fragA
  • 您可以在這種情況下,旋轉重現該問題。這是 容易得多。
  • 閱讀片段整個doc
+0

很清楚了!非常感謝! – Suxsem

0

以及我猜GC無關,與你的問題,你可以做什麼,就是要遵循LifeCycle

@Override onPause() & onStop // and see what happens. 

,看看這個鏈接獲取更多信息Android Life Cycle