Android的findFragmentByTag调试时返回null [英] Android findFragmentByTag returns null when debugging

查看:388
本文介绍了Android的findFragmentByTag调试时返回null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:

我写与可以由许多片段中的一个被填充的活动Android应用程序。比较经常,我需要的数据的一个包传递到活性片段,以便它可以相应地更新用户界面。

I am writing an android application with an activity that can be populated by one of a number of fragments. Relatively often, I need to pass a bundle of data to the active fragment so that it can update the UI accordingly.

要获得当前的片段,我称之为 getfragmentManager()。findFragmentByTag()和转换返回的片段我定制的片断类。

To get the current fragment, I call getfragmentManager().findFragmentByTag() and cast the returned fragment to my custom fragment class.

问题:

以上方法通常工作正常。然而, findFragmentByTag()偶尔返回null。经进一步调查,我得出的结论是,当我运行或从Android的工作室调试(即使这样它不会发生每次),这只会发生。

The above method usually works fine. However, findFragmentByTag() occasionally returns null. Upon further investigation, I have concluded that this will only occur when I run or debug from Android studio (and even then it doesn't happen every time).

相关code:

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看起来是这样的:

Normally, my logcat looks something like this:

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中的应用程序,我得到的是这样的:

But every now and then, and only when I start the app from Android Studio, I get something like:

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

在地球上这到底是怎么回事?

What on Earth is going on here?

更新:

我已经能够通过单击应用程序切换按钮,关闭我的应用程序,并立即重新启动它重现此错误断开连接时,从Android的工作室。只要我做这个速度不够快,它永远不会失败,因为我上述的行为。

I have been able to reproduce this error while disconnected from Android Studio by clicking the app switch button, closing my app and immediately restarting it. Provided I do this quickly enough, it never fails to behave as I described above.

在一些记录和追逐等问题,我发现,在这些特殊情况下,的onCreate()被调用两次。

After some more logging and chasing down other issues, I discovered that in these particular cases, onCreate() is being called twice.

我的应用程序被设计成只在横向模式下运行,部分原因是为了避免与来重新创建活动的问题。不过,看来,当应用程序被关闭并重新启动迅速的Andr​​oid无法完成必要的旋转为纵向模式,主屏幕我的应用程序被再次启动之前。我的假设是,这会导致操作系统的应用程序正在运行后转回景观,从而重新启动它。

My app is designed to run only in landscape mode, in part to avoid issues that come with recreating the activity. It would seem, however, that when the app is closed and restarted quickly, Android never finishes the necessary rotation to portrait mode for the home screen before my app is launched again. My assumption is that this causes the OS to rotate back to landscape after the app is running and thereby restart it.

这一切是罚款和花花公子,除了事实,它并不能解释为什么 findFragmentByTag()有时返回null。

All of this is fine and dandy, except for the fact that it doesn't explain why findFragmentByTag() sometimes returns null.

在我的Activity类的每个对象应重新创建,对不对?所以应该不是FragmentManager重新初始化呢?或者是 getFragmentManager()的静态引用的东西活动本身之外吗?

Every object in my Activity class should be recreated, right? So shouldn't the FragmentManager be re-initialized as well? Or is getFragmentManager() a static reference to something outside of the Activity itself?

第二次更新:

我试过检查的乔治的想法,如果已经添加的片段我打电话之前的BeginTransaction(),虽然它并没有解决这个问题,我发现了一些奇怪调试时:

I tried George's idea of checking if the fragment had already been added before I call beginTransaction() and, although it didn't solve the problem, I noticed something strange when debugging:

我设置为断点Log.d(TAG,返回片段为空); 。关闭应用程序,并迅速重新启动它保证正如我上面提到的这code必达。然后,如果我通过调用查看片段管理器 getFragmentManager()在评估前pression窗口,我注意到一个'登录片段已经被添加,但它不具有与它相关联的标签。

I set a breakpoint at Log.d(TAG, "Fragment returned is null.");. Closing the app and quickly restarting it guarantees that this code will be reached as I mentioned above. Then, if I view the Fragment Manager by calling getFragmentManager() in the Evaluate Expression window, I notice that a `Login Fragment' has already been added, but it doesn't have a tag associated with it.

在设置断点 Log.d(TAG,返回片段是有效的。); 在同一应用程序会话,但是,揭示了 LoginFragment 中加入例如预计的标签。

Setting a breakpoint at Log.d(TAG, "Fragment returned is valid.");in the same app session, however, reveals the LoginFragment is added with a tag as would be expected.

有在我的code不会点哪里我曾经添加一个片段不设置标签。难道这有什么做的活动正在重建和碎片经理失去的标签,即使它持有到碎片自己?

There is no point in my code where I ever add a fragment without setting a tag. Could this have something to do with the activity being recreated and the Fragment manager losing tags even though it holds onto the fragments themselves?

推荐答案

有几件事情要注意这一点。
updateFragment 你应该使用比较真的你的字符串 .equals 而不是引用比较 == 所以 LOGIN_FRAGMENT_TAG.equals(currentFragmentTag)作为最佳实践,避免混淆。

A few things to note on this. In updateFragment you should really compare your Strings using .equals instead of reference comparison == so LOGIN_FRAGMENT_TAG.equals(currentFragmentTag)as a best practice and to avoid confusion.

此外, FragmentManager 将记住哪些片段已跨方向的变化添加到它。因此,在一个例子你提到,你进入的onCreate 两次,你会那么可能有两个实例,你的 LoginFrag 上后退堆栈。

Also, the FragmentManager will remember which fragments you have added to it across orientation changes. So in the one example you mentioned where you get into onCreate twice you will then likely have two instances of your LoginFrag on the back stack.

您可以通过做你在你的 updateFragment 方法做同样的查找,只增加的片段,如果没有找到避免这种情况。

You can avoid this by doing the same lookup you are doing in your updateFragment method and only adding the fragment if it isn't found.

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

我猜多个片段在本次活动使用,因为你懒得具有字符串 currentFragmentTag ,但如果没有,那么这将是你最好只保留一个参考你的 LoginFragment 作为类中的字段,这样就可以避免它在 updateFragment 方法额外的查找。

I'm guessing multiple fragments are used in this activity since you bother having the String currentFragmentTag but if not then it would be better for you to just keep a reference to your LoginFragment as a field on the class so you can avoid the additional lookup of it in the updateFragment method.

除此之外,我试图重现你的错误,我不能让错误可能在code你是不是出在别处。

Other than that I tried reproducing your error and I cannot so the error might be elsewhere in code you are not showing.

这篇关于Android的findFragmentByTag调试时返回null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆