我有一个垃圾收集问题(我认为)。
让我解释:

这是我的活动的简化版本:

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,按家庭按钮(并执行需要ram等操作,例如浏览或观看youtube视频),返回我的应用程序,按其他按钮(在片段B中)... fragA为空!!!

但是该应用程序并未完全重新创建,因为当我返回它时,片段B是可见的,就像该应用程序永远不会自行关闭一样。

所以...您能解释一下这种现象以及如何解决吗?

非常感谢!

最佳答案

但是该应用程序并未完全重新创建,因为当我返回到该应用程序时,
  片段B是可见的,就像该应用程序永远不会自行关闭一样。


那是错误的。您的应用程序可能会被完全重新创建,但是fragB会被系统重新加载,因为它在按下主页按钮(在本例中为R.id.container)时已附加到容器上。

在所描述的场景中,savedInstanceState不为null,因此您的代码将不会创建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为null,但实际上fragB也为null,因此您从未在代码中使用该引用。

原因是系统只是为您重新创建了片段,但正式地,这不会使您的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片段!

关于java - fragment 和垃圾收集器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24720722/

10-12 05:03