【问题标题】:Fragment - getArguments() returns an empty bundle片段 - getArguments() 返回一个空包
【发布时间】:2017-04-24 20:48:52
【问题描述】:

希望有人能帮助我理解这一点:

  1. 我正在使用单活动应用程序和许多在同一个容器中替换的片段,并且我正在启用“不保留活动”选项的真实设备中测试我的应用程序

  2. 添加新片段时(使用@987654321@ 方法),我正在使用@987654322@ 方法将信息传递给新片段。它按预期工作,我可以在该片段中使用@987654323@ 获取该信息。到目前为止一切正常...

  3. 之后,我将我的应用程序发送到后台。我看到堆栈中的所有片段都被破坏了,正如预期的那样

  4. 我将我的应用程序带到前台,在 getArguments() 方法中,我得到一个空的 Bundle(不是 null,只是一个空对象),而不是带有我在 #2 中使用的数据的那个

根据 Android 文档,setArguments() 中提供的参数将在片段销毁和创建过程中保留...所以,我的问题是:

  1. “将在片段销毁和创建之间保留”是否包括我描述的场景?

  2. 如果启用“不保留活动”选项,是否会与getArguments()/setArguments() 混淆?

  3. 除了“不保留活动”选项之外,还有其他方法可以测试正确的片段创建/销毁吗?

  4. 正确保持片段参数“活动”的更好方法是什么?我可以将它们保存在onSaveInstanceState() 方法中,但想知道除此之外是否还有更多选项。

【问题讨论】:

  • 你试过支持片段吗?至少它们在所有平台上的行为都是一致的。排除故障可能更容易。
  • @EugenPechanec 我正在使用支持片段
  • 您介意分享一些代码吗?
  • @Reyansh Mishra 我不能,因为该项目来自工作,而不是我的。我将尝试创建一个仅具有片段事务功能的示例项目来验证 getArguments 问题
  • 太奇怪了,我也遇到了同样的问题。

标签: android android-fragments android-lifecycle fragmentmanager


【解决方案1】:

活动和片段娱乐是我们团队特别关注的重点之一。所以这是我们想到的一些项目符号。

  1. “将在片段销毁和创建之间保留”是否包括我描述的场景?

请记住,“不要保留活动”会在您进入后台时破坏您的活动。稍后系统将尝试恢复您的上一个状态,自动重新创建最后一个 Activity 及其片段。 Android 将保存必要的信息以恢复其最后状态。所以是的,你的场景应该被覆盖。

  1. 如果启用“不保留活动”选项,是否会与 getArguments()/setArguments() 混淆?

根据您的流程,您可以尝试一些问题。当活动重新创建时 onCreate 方法上的 savedInstanceState 将不为空。您应该使用此信息来避免重新创建或重新附加您的片段。系统会尝试为你恢复,这就是片段不能有任何构造函数的原因。

  1. 除了“不保留活动”选项之外,还有其他方法可以测试正确的片段创建/销毁吗?

使用 FragmentTransaction。

1 - 使用 FragmentTransaction 将您的片段添加到您的活动,而不将其添加到后台堆栈。

2 - 使用 FragmentTransaction 将前一个 Fragment 替换为其他 Fragment(或者可能是前一个 Fragment 的新实例)。当一个片段被其他片段替换并且它没有被添加到后台堆栈时,android会销毁它。

  1. 正确保持片段参数“活跃”的更好方法是什么?我可以将它们保存在 onSaveInstanceState() 方法中,但想知道除此之外是否还有更多选项。

您可能不需要在代码中保留参数包。安卓会为你做这件事。但是在 onAttach 方法(当片段将在屏幕上可用时调用的第一个方法)中恢复捆绑数据并将它们存储为类属性以供以后使用是一个很好的做法。

【讨论】:

  • 我在更改片段时使用 FragmentTransaction.replace。我也使用 addToBackStack 方法。现在,我在 onCreateView 方法中使用 getArguments。我会尝试将其移至 onAttach 并测试您的建议
  • @jDur stackoverflow.com/questions/67042935/… 帮帮我兄弟我需要答案
【解决方案2】:

我猜问题是每次调用活动的onCreate 时都会创建一个新的片段实例。假设您当前的代码如下所示:

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

    ...
    ...
    fragment = SampleFragment.newInstance("sample");
    getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.container, fragment, "sample_fragment_tag")
            .commit();
    ...
}

因此,每次重新创建活动时,都会创建一个新的片段实例并将其附加到活动。只有当savedInstanceStatenull 时,您才应该避免这种情况并创建片段的新实例,这意味着您的活动刚刚创建。否则,保存的片段实例将连同其参数连同活动实例一起恢复:

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

    ...
    ...
    if (savedInstanceState == null) {
        fragment = SampleFragment.newInstance("sample");
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.container, fragment, "sample_fragment_tag")
                .commit();
    } else {
        fragment = (SampleFragment) getSupportFragmentManager().findFragmentByTag("sample_fragment_tag");
    }
    ...
}

希望,这就是你要找的。​​p>

【讨论】:

  • 我的代码中已经有 savedInstanceState != null 行,以防止您描述的内容。它之所以有效,是因为片段堆栈与 Activity 被销毁时相同,只是顶部的片段在 getArguments() 中具有空包
  • 在生命周期内何时调用 getArguments?可以发一些代码吗?
  • @BjörnKechel 我不能,因为该项目来自工作,而不是我的。我将尝试创建一个仅具有片段事务功能的示例项目来验证 getArguments 问题
  • @allo86 stackoverflow.com/questions/67042935/… 帮帮我兄弟我需要答案
【解决方案3】:

感谢大家的回答。我仍然不知道为什么我会遇到这个问题。我创建了一个示例项目来仅测试片段事务并将其发布在@Reyansh 和@Björn 要求的此处。这是一个非常简单的项目,并且 - 猜猜看 - 我无法在该项目中重现该问题:getArguments() 方法在每次重新创建活动时都会提供相同的 Bundle。所以,一定是我的项目中的其他东西导致了这种奇怪的行为。

我决定将@jDur 的答案标记为正确的答案,因为它可以很好地解释我的问题。

【讨论】:

    【解决方案4】:

    据我所知,提供不保留活动选项是为了在内存不足的情况下测试您的应用程序,并且当其他资源无法为您的应用程序提供服务时,Android 操作系统会终止您的应用程序。 那时您有机会使用 onSavedInstanceState 保存数据,在片段中您可以使用 setRetainState(true) 根据我保存捆绑数据的经验,使用 sharedPreferences。 在您从设置中卸载或清除应用程序数据或通过 SharedPreference Editor 以编程方式将其删除之前,SharedPreference 永远不会被破坏。 有一点很清楚,如果 Activity 被销毁,那么它的所有 Fragment 肯定会被销毁。 希望你明白我的意思。

    【讨论】:

    • 根据 Android 文档,setArguments() 中提供的参数将在片段销毁和创建过程中保留 ...仍然没有解释为什么在这种情况下,在活动和片段销毁,getArguments 未提供与 setArguments() 中使用的相同的 Bundle。
    • setRetainInstance 在配置更改时起作用。当活动被杀死时它没有帮助,这是由Don't keep activities 选项模拟的。在所有情况下,您都应该使用onSaveInstanceState。并且附加的片段也确实被保存了。但这与手头的问题无关。
    • 请分享您的代码。你如何在片段中传递数据?
    【解决方案5】:
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    /*Created by Foolish_Guy on 4/29/2017.*/                 
    
    public class TestFragment extends Fragment {
    private static final String USER_ID = "param1";
    private static final String ARG_PARAM2 = "param2";
    
    String userID;
    String mParam2;
    
    public static TestFragment newInstance(String param1, String param2) {
        TestFragment fragment = new TestFragment();
        Bundle args = new Bundle();
        Log.e("Data :", String.valueOf(param1));
        args.putString(USER_ID, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }
    
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            userID = getArguments().getString(USER_ID);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }
    
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        return view;
    }
    

    }

    当您初始化片段时,您需要提供所需的参数。 您正在通过调用

    对其进行初始化
    TestFragment frag = TestFragment.newInstance("UID", "TEXT");
    

    一旦调用它,就会设置 Bundle 参数

    onCreate (Bundle savedInstance) 中的下一个将被调用, 现在 Bundle 不会为空。

    【讨论】:

    • 这就是我正在做的事情
    【解决方案6】:

    onSaveInstanceState 是当应用程序被销毁但仍在最近的应用程序列表中时保存数据的最佳位置。您节省的钱足以重建您的应用程序在发送到后台时的外观,这就是用户离开您的应用程序的地方。用户将应用程序置于后台两到三周,然后将其带到前面并微笑它记得它在哪里。

    在偏好保存状态下,您的应用程序的用户会将他们的手机扔到墙上。他们将从最近的应用程序中清除该应用程序,然后重新启动,然后永久卸载您的应用程序,因为有一次从最近的应用程序中删除它并没有从一开始就启动,并且他们希望该应用程序从一开始就启动。我把你弄丢了吗?

    【讨论】:

    • 我知道 onSaveInstanceState。问题是我很困惑为什么我在 getArguments 中得到一个空包,而不是我在 setArguments 中放入的数据包
    • 这与获取参数不同。只有纯种 Android 应用程序使用 onsaveinstancestate 如果您不知道如何使用,您将提出一个新问题
    • 我也使用 onSaveInstanceState,但这个问题是关于我在使用真实设备(带有 Android 6.0 的 Nexus 6)和 getArguments 方法的应用中发现的问题
    【解决方案7】:
    setRetainInstance(true);
    

    在片段的 onCreate 方法中。在通过标签从 SupportFragmentManager 中添加或替换片段之前,如果片段值为空,则添加或替换为新片段。喜欢

    Fragment fragment = fragmentManager.findFragmentByTag(tag);
    if(fragment==null){
     fragmentManager.beginTransaction().replace(...
    }
    

    【讨论】:

    • 我在后台堆栈中使用片段。 setRetainInstance 在这种情况下不起作用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-13
    • 2016-09-20
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多