当前位置:  开发笔记 > 编程语言 > 正文

调试时,Android findFragmentByTag返回null

如何解决《调试时,AndroidfindFragmentByTag返回null》经验,为你挑选了1个好方法。

背景:

我正在编写一个Android应用程序,其活动可以由许多片段中的一个填充.相对而言,我需要将一组数据传递给活动片段,以便它可以相应地更新UI.

为了获取当前片段,我调用getfragmentManager().findFragmentByTag()并将返回的片段转换为我的自定义片段类.

问题:

上述方法通常可以正常工作.但是,findFragmentByTag()偶尔会返回null.经过进一步调查,我得出的结论是,只有当我从Android工作室运行或调试时才会发生这种情况(即使这样,每次都不会发生).

相关守则:

protected void onCreate(Bundle savedInstanceState){

    //Do lots of stuff
    currentFragmentTag = "";
    getFragmentManager().addOnBackStackChangedListener(
            new FragmentManager.OnBackStackChangedListener() {
                public void onBackStackChanged() {
                    if (getFragmentManager().getBackStackEntryCount() > 0) {
                        currentFragmentTag = getFragmentManager().getBackStackEntryAt(getFragmentManager().getBackStackEntryCount() - 1).getName();
                    }

                }
            });
    init();

    //Do some more stuff

    //this should always be the case
    if (currentFragmentTag.equals(LOGIN_FRAGMENT_TAG)) {
        ((LoginFragment) getFragmentManager().findFragmentByTag(currentFragmentTag)).beginLogin();
    }

}


private void init(){
    //changed to reflect George Mulligan's advice
    Fragment currentFrag = getFragmentManager().findFragmentByTag(LOGIN_FRAGMENT_TAG);
    if(currentFrag == null) {
        currentFragmentTag = LOGIN_FRAGMENT_TAG;
        getFragmentManager().beginTransaction()
                .add(R.id.container, loginFrag, LOGIN_FRAGMENT_TAG)
                .addToBackStack(LOGIN_FRAGMENT_TAG)
                .commit();
        getFragmentManager().executePendingTransactions();

    }
}

public void updateFragment(){
    Bundle dataBundle = new Bundle();
    //put stuff in dataBundle

    if (currentFragmentTag.equals(LOGIN_FRAGMENT_TAG)) {
        LoginFragment currentFrag = (LoginFragment) getFragmentManager().findFragmentByTag(currentFragmentTag);
        if (currentFrag != null) {
            currentFrag.passBundleToFragment(dataBundle);
            Log.d(TAG, "Fragment returned is valid.");
        } else {
            Log.d(TAG, "Fragment returned is null.");
        }
    } 
    //else if a different fragment is active then update it in the same way
}

//Manually open the loginFragment. This can be called from other fragments. My problem always occurs before this is called however. 
@Override
public void openLoginScreen() {
    if(/*some conditions*/) {
        LoginFragment loginFrag = LoginFragment.newInstance();
        getFragmentManager().beginTransaction()
                .replace(R.id.container, loginFrag, LOGIN_FRAGMENT_TAG)
                .addToBackStack(LOGIN_FRAGMENT_TAG)
                .commit();
        getFragmentManager().executePendingTransactions();
        currentFragmentTag = LOGIN_FRAGMENT_TAG;
        updateFragment();
    }
}

通常,我的logcat看起来像这样:

Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
...etc.

但是时不时地,只有当我从Android Studio启动应用程序时,我得到的结果如下:

Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is valid
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is null
Fragment returned is valid
Fragment returned is valid

地球上到底发生了什么?

更新:

通过单击应用程序切换按钮,关闭我的应用程序并立即重新启动它,我可以在与Android Studio断开连接时重现此错误.如果我足够快地做到这一点,它永远不会像我上面描述的那样表现.

经过一些记录和追逐其他问题,我发现在这些特殊情况下,onCreate()被调用两次.

我的应用程序设计为仅在横向模式下运行,部分是为了避免重新创建活动时出现的问题.但是,当应用程序关闭并快速重新启动时,Android似乎永远不会在我的应用程序再次启动之前完成主屏幕的纵向模式的必要旋转.我的假设是,这会导致操作系统在应用程序运行后旋转回横向状态,从而重新启动它.

所有这一切都很好,花花公子,除了它没有解释为什么findFragmentByTag()有时会返回null.

我的Activity类中的每个对象都应该重新创建,对吧?那么FragmentManager也不应该重新初始化吗?或者是getFragmentManager()对Activity本身之外的东西的静态引用?

第二次更新:

我尝试了George在调用之前检查片段是否已经添加的想法beginTransaction(),尽管它没有解决问题,但我在调试时注意到了一些奇怪的事情:

我设定了一个断点Log.d(TAG, "Fragment returned is null.");.关闭应用程序并快速重新启动它可确保按照我上面提到的那样访问此代码.然后,如果我通过getFragmentManager()在Evaluate Expression窗口中调用来查看片段管理器,我注意到已经添加了"Login Fragment",但它没有与之关联的标记.

Log.d(TAG, "Fragment returned is valid.");但是,在同一个应用程序会话中设置断点会显示LoginFragment添加了一个预期的标记.

我的代码中没有任何意义,我在没有设置标签的情况下添加片段.这可能与正在重新创建的活动和Fragment管理器丢失标签有关,即使它保留在片段本身上吗?



1> George Mulli..:

关于这一点需要注意几点.在updateFragment你应该真正比较你的字符串使用.equals而不是参考比较,==LOGIN_FRAGMENT_TAG.equals(currentFragmentTag)作为最佳做法,并避免混淆.

此外,FragmentManager还会记住您在方向更改时添加了哪些片段.因此,在一个例子中,你提到了你进入onCreate两次的位置,那么你可能会LoginFrag在后面的堆栈上有两个你的实例.

您可以通过在updateFragment方法中执行相同的查找来避免这种情况,并且只在未找到时添加片段.

LoginFragment currentFrag = (LoginFragment) getFragmentManager()
    .findFragmentByTag(LOGIN_FRAGMENT_TAG);

if(currentFrag == null) {
    currentFrag = getFragmentManager().beginTransaction()
        .replace(R.id.container, loginFrag, LOGIN_FRAGMENT_TAG)
        .addToBackStack(LOGIN_FRAGMENT_TAG)
        .commit();

    //executePendingTransactions() usually isn't necessary...
    getFragmentManager().executePendingTransactions();
}

我猜这个活动中使用了多个片段,因为你打扰了String currentFragmentTag但是如果没有那么你最好只保留对你LoginFragment作为一个字段的引用,这样你就可以避免在的updateFragment方法.

除此之外我尝试重现你的错误,我不能这样错误可能在你没有显示的代码中的其他地方.

推荐阅读
echo7111436
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有