片段 - getArguments() returns 一个空包
Fragment - getArguments() returns an empty bundle
希望有人能帮助我理解这一点:
我正在使用单个 activity 应用程序和许多在同一个容器中替换的片段,我正在使用 "Don't keep activities"选项启用
添加新片段时(在该片段中使用 <a href="https://developer.android.com/reference/android/app/FragmentTransaction.html#replace(int,%20android.app.Fragment,%20java.lang.String)" rel="noreferrer">FragmentTransaction replace()</a>
method), I am using the <a href="https://developer.android.com/reference/android/app/Fragment.html#setArguments(android.os.Bundle)" rel="noreferrer">setArguments()</a>
method to pass information to the new Fragment. It works as expected and I can get that information with <a href="https://developer.android.com/reference/android/app/Fragment.html#getArguments()" rel="noreferrer">getArguments()</a>
。到目前为止一切正常...
在此之后,我将我的应用程序发送到后台。我看到堆栈中的所有片段都被销毁了,再次如预期
我把我的应用程序带到前台,在 getArguments()
方法中我得到一个空的 Bundle
(不是空的,只是一个空的对象)而不是那个我在#2
中使用的数据
根据 Android 文档,setArguments()
中提供的参数将在片段销毁和创建过程中保留...所以,我的问题是:
"will be retained across fragment destroy and creation"是否包括我描述的场景?
如果启用 "Don't keep activities" 选项是否会与 getArguments()
/setArguments()
混淆?
除了 "Don't keep activities" 选项之外,还有其他方法可以测试正确的片段 creation/destroy 吗?
正确保留片段参数的更好方法是什么"alive"?我可以将它们保存在 onSaveInstanceState() 方法中,但想知道除此之外是否还有更多选项。
据我所知,不保留活动选项用于在内存不足的情况下测试您的应用程序,当其他资源无法为您的应用程序提供服务时,Android OS 终止了您的应用程序。
那时你有机会使用 onSavedInstanceState 保存数据,在片段中你可以使用 setRetainState(true)
根据我保存包数据的经验,使用 sharedPreferences。
SharedPreference 永远不会被销毁,直到您从设置中卸载或清除应用程序数据或通过 SharedPreference Editor 以编程方式将其删除。
有一件事很清楚,如果 activity 被销毁,那么它的所有碎片肯定会被销毁。
希望你明白我的意思。
我想问题是每次调用 activity 的 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();
...
}
因此,每次重新创建 activity 时,都会创建一个新的片段实例并将其附加到 activity。您应该避免这种情况,并且仅当 savedInstanceState
为 null
时才创建片段的新实例,这意味着您的 activity 刚刚创建。否则,保存的片段实例将连同其参数以及 activity instance:
一起恢复
@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");
}
...
}
希望,这就是您要找的。
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 不会是空的了。
onSaveInstanceState 是应用被销毁但仍在最近应用列表中时保存数据的最佳位置。您节省的钱刚好足以重建您的应用程序在发送到后台时的外观,这就是用户离开您的应用程序的地方。用户将应用程序置于后台两三个星期,然后将其带到前台并微笑它记得它在哪里。
在首选项中,保存状态将使您的应用程序的用户将他们的 phone 扔到墙上。他们将从最近的应用程序中清除该应用程序,然后重新启动,然后永久卸载您的应用程序,因为它不是从一开始就从最近的应用程序中删除的,他们希望该应用程序从一开始就启动。我失去你了吗?
Activity和碎片化游戏是我们团队特别关注的点之一。所以这是我们想到的一些项目符号。
- "will be retained across fragment destroy and creation"是否包括我描述的场景?
请记住,当您进入后台时,"Don't keep Activities" 正在摧毁您的 Activity。稍后系统将尝试恢复您的最后状态,自动重新创建最后一个 Activity 及其片段。
Android 将保存必要的信息以恢复其最后状态。所以是的,应该涵盖您的场景。
- 如果启用 "Don't keep activities" 选项,它是否会与 getArguments()/setArguments() 混淆?
根据您的流程,您可以尝试一些问题。当 activity 在 onCreate 方法上重新创建 savedInstanceState 时将不为空。您应该使用此信息来避免重新创建或重新附加您的片段。系统会尝试为你恢复它,这就是片段不能有任何构造函数的原因。
- 除了 "Don't keep activities" 选项之外,还有其他方法可以测试正确的片段 creation/destroy 吗?
使用 FragmentTransaction。
1 - 使用 FragmentTransaction 将片段添加到 activity 而无需将其添加到后台堆栈。
2 - 使用 FragmentTransaction 将前一个片段替换为其他片段(或者可能是前一个片段的新实例)。当一个片段被其他片段替换并且它没有被添加到返回堆栈时 android 销毁它。
- 正确保留片段参数的更好方法是什么 "alive"?我可以将它们保存在 onSaveInstanceState() 方法中,但想知道除此之外是否还有更多选项。
可能您不需要在代码中保留参数包。 Android 会为您完成。但在 onAttach 方法(当片段将在屏幕上可用时调用的第一个方法)中恢复包数据并将它们存储为 class 属性供以后使用是一个很好的做法。
setRetainInstance(true);
在fragment的onCreate方法中。在通过标记从 SupportFragmentManager 添加或替换片段之前,如果片段值为空,则添加或替换为新片段。喜欢
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if(fragment==null){
fragmentManager.beginTransaction().replace(...
}
感谢大家的回答。我仍然不知道为什么我会遇到这个问题。我创建了一个示例项目来仅测试片段事务和 post 它在这里作为 @Reyansh 和 @Björn 询问。这是一个非常简单的项目 - 你猜怎么着 - 我无法重现该项目中的问题:每次重新创建 activity 时,getArguments() 方法都会提供相同的 Bundle。所以,一定是我项目中的其他原因导致了这种奇怪的行为。
我决定将@jDur 的答案标记为正确答案,因为它很好地解释了我的问题。
希望有人能帮助我理解这一点:
我正在使用单个 activity 应用程序和许多在同一个容器中替换的片段,我正在使用 "Don't keep activities"选项启用
添加新片段时(在该片段中使用
<a href="https://developer.android.com/reference/android/app/FragmentTransaction.html#replace(int,%20android.app.Fragment,%20java.lang.String)" rel="noreferrer">FragmentTransaction replace()</a>
method), I am using the<a href="https://developer.android.com/reference/android/app/Fragment.html#setArguments(android.os.Bundle)" rel="noreferrer">setArguments()</a>
method to pass information to the new Fragment. It works as expected and I can get that information with<a href="https://developer.android.com/reference/android/app/Fragment.html#getArguments()" rel="noreferrer">getArguments()</a>
。到目前为止一切正常...在此之后,我将我的应用程序发送到后台。我看到堆栈中的所有片段都被销毁了,再次如预期
我把我的应用程序带到前台,在
getArguments()
方法中我得到一个空的Bundle
(不是空的,只是一个空的对象)而不是那个我在#2 中使用的数据
根据 Android 文档,setArguments()
中提供的参数将在片段销毁和创建过程中保留...所以,我的问题是:
"will be retained across fragment destroy and creation"是否包括我描述的场景?
如果启用 "Don't keep activities" 选项是否会与
getArguments()
/setArguments()
混淆?除了 "Don't keep activities" 选项之外,还有其他方法可以测试正确的片段 creation/destroy 吗?
正确保留片段参数的更好方法是什么"alive"?我可以将它们保存在 onSaveInstanceState() 方法中,但想知道除此之外是否还有更多选项。
据我所知,不保留活动选项用于在内存不足的情况下测试您的应用程序,当其他资源无法为您的应用程序提供服务时,Android OS 终止了您的应用程序。 那时你有机会使用 onSavedInstanceState 保存数据,在片段中你可以使用 setRetainState(true) 根据我保存包数据的经验,使用 sharedPreferences。 SharedPreference 永远不会被销毁,直到您从设置中卸载或清除应用程序数据或通过 SharedPreference Editor 以编程方式将其删除。 有一件事很清楚,如果 activity 被销毁,那么它的所有碎片肯定会被销毁。 希望你明白我的意思。
我想问题是每次调用 activity 的 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();
...
}
因此,每次重新创建 activity 时,都会创建一个新的片段实例并将其附加到 activity。您应该避免这种情况,并且仅当 savedInstanceState
为 null
时才创建片段的新实例,这意味着您的 activity 刚刚创建。否则,保存的片段实例将连同其参数以及 activity instance:
@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");
}
...
}
希望,这就是您要找的。
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 不会是空的了。
onSaveInstanceState 是应用被销毁但仍在最近应用列表中时保存数据的最佳位置。您节省的钱刚好足以重建您的应用程序在发送到后台时的外观,这就是用户离开您的应用程序的地方。用户将应用程序置于后台两三个星期,然后将其带到前台并微笑它记得它在哪里。
在首选项中,保存状态将使您的应用程序的用户将他们的 phone 扔到墙上。他们将从最近的应用程序中清除该应用程序,然后重新启动,然后永久卸载您的应用程序,因为它不是从一开始就从最近的应用程序中删除的,他们希望该应用程序从一开始就启动。我失去你了吗?
Activity和碎片化游戏是我们团队特别关注的点之一。所以这是我们想到的一些项目符号。
- "will be retained across fragment destroy and creation"是否包括我描述的场景?
请记住,当您进入后台时,"Don't keep Activities" 正在摧毁您的 Activity。稍后系统将尝试恢复您的最后状态,自动重新创建最后一个 Activity 及其片段。 Android 将保存必要的信息以恢复其最后状态。所以是的,应该涵盖您的场景。
- 如果启用 "Don't keep activities" 选项,它是否会与 getArguments()/setArguments() 混淆?
根据您的流程,您可以尝试一些问题。当 activity 在 onCreate 方法上重新创建 savedInstanceState 时将不为空。您应该使用此信息来避免重新创建或重新附加您的片段。系统会尝试为你恢复它,这就是片段不能有任何构造函数的原因。
- 除了 "Don't keep activities" 选项之外,还有其他方法可以测试正确的片段 creation/destroy 吗?
使用 FragmentTransaction。
1 - 使用 FragmentTransaction 将片段添加到 activity 而无需将其添加到后台堆栈。
2 - 使用 FragmentTransaction 将前一个片段替换为其他片段(或者可能是前一个片段的新实例)。当一个片段被其他片段替换并且它没有被添加到返回堆栈时 android 销毁它。
- 正确保留片段参数的更好方法是什么 "alive"?我可以将它们保存在 onSaveInstanceState() 方法中,但想知道除此之外是否还有更多选项。
可能您不需要在代码中保留参数包。 Android 会为您完成。但在 onAttach 方法(当片段将在屏幕上可用时调用的第一个方法)中恢复包数据并将它们存储为 class 属性供以后使用是一个很好的做法。
setRetainInstance(true);
在fragment的onCreate方法中。在通过标记从 SupportFragmentManager 添加或替换片段之前,如果片段值为空,则添加或替换为新片段。喜欢
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if(fragment==null){
fragmentManager.beginTransaction().replace(...
}
感谢大家的回答。我仍然不知道为什么我会遇到这个问题。我创建了一个示例项目来仅测试片段事务和 post 它在这里作为 @Reyansh 和 @Björn 询问。这是一个非常简单的项目 - 你猜怎么着 - 我无法重现该项目中的问题:每次重新创建 activity 时,getArguments() 方法都会提供相同的 Bundle。所以,一定是我项目中的其他原因导致了这种奇怪的行为。
我决定将@jDur 的答案标记为正确答案,因为它很好地解释了我的问题。