我知道“newInstance”-Pattern(Best practice for instantiating a new Android Fragment)。但是,如果更新数据,如何更新片段的这些参数呢?
我知道片段/活动之间的回调方法,但这些回调不会更新参数?!
例如:在创建片段时,我使用bundle将URI传递给它。 然后另一个片段通过第一个片段上的changeUri(Uri uri)方法回调来更改此URI。 如果然后片段被重新创建(例如由于屏幕旋转),它将使用参数包中的第一个URI而不是后来更新的uri,对吗?
解决此问题的最佳做法是什么?我是否必须手动将其存储在savedInstanceState中,并在使用时决定是使用instanceState还是arguments-bundle?
我正在寻找一种处理我的片段参数的标准方法,所以我想我会采用这种方法(伪代码):
private Uri arg1;
public static Fragment newInstance(Uri arg1) {
create bundle
create fragment instance
set bundle to fragment
return fragment
}
private void onCreate(Bundle savedInstance) {
if(savedInstance != null) {
arg1 = savedInstance.uri
}
}
private Uri getUri() {
if(arg1 == null) {
arg1 = getArguments.uri
}
if(arg1 == null) {
arg1 = defaultValue
}
}
所以我有一种简单统一的方式来访问我的论点。每次我需要这个论点时,都不必使用if-else-hassle。
你怎么看?
答案 0 :(得分:21)
一旦设置了Fragment
并将Activity
添加到Bundle
,就无法更改参数,我使用了您自己定义的类似方法。
首先,我检查了传递给onCreate()
的{{1}},如果它不是null我使用它,但如果它为null,那么我使用参数。我保存onSaveInstanceState()
中的最新数据。
有关详情:Is it possible to pass arguments to a fragment after it's been added to an activity?
答案 1 :(得分:4)
您可以像处理片段onSaveInstanceState回调中的活动一样保存状态。如果您自上次onCreate()
以来更新了URI,则会将更新后的URI存储在Bundle
中,并会在onCreate()
中重新收到。保存状态正是它的设计目标,通过更改URI,您所做的就是更改状态。
答案 2 :(得分:4)
我只是更改了包中的值。
示例:强>
synchronized (fragment.getArguments()) {
fragment.getArguments().putInt(KEY, new Value);
}
使用新的Argument
更新内容答案 3 :(得分:1)
Best practice for updating arguments of a fragment
:为什么我们需要通过NewInstance()
方法&添加参数为什么它是片段的最佳实践?
片段可以被视为活动的模块化部分。这意味着当我们创建一个片段时,我们需要使它成为模块化的。独立的。
假设你需要一个需要参数来操作的片段。我们也可以写它
MyFragmentClass mFrag = new MyFragmentClass();
Bundle bundle = new Bundle();
bundle.putString("key", value);
mFrag.setArguments(bundle);
它也很好用&你可以得到参数onCreate
方法。不同之处在于您还可以在不使用参数的情况下创建片段实例,并将其添加到片段管理器中,但您的片段需要参数才能运行。在片段中添加newInstance
方法会强制开发人员在创建时添加参数。这就是最佳实践的原因。
在你的问题中你可以使用setRetainInstance(boolean retain)
来防止你的片段在活动被破坏时不被破坏。
答案 4 :(得分:0)
根据您使用片段的方式,可能会确定该策略的效果。
例如,如果在公共选项卡/视图分页器模式中有许多片段并使用FragmentStatePagerAdapter管理它们,则您的活动或其他片段可能有机会引用不再存在的片段实例,从而导致空指针异常。
如果你不想编写回调,你可以解决这个问题的方法是使用Intents和BroadcastReceivers(这可能有点过分且难以管理,但如果正确完成可以节省很多我的经验令人头疼)向父母活动发送和接收广播。
关于意图的美妙之处在于它们可以在特定时间进行调整,并接受各种数据附加功能,包括捆绑包和可包裹的对象。
答案 5 :(得分:0)
如果你想重用一个片段但需要更新参数,你需要使用 fragment.getArguments()。putAll(bundle);
private static void setInspireByDoArguments(DoOptionsFragment fragment, long doId) {
Bundle bundle = new Bundle();
bundle.putLong(Constants.EXTRA_DO_ID, doId);
bundle.putInt(Constants.EXTRA_DO_OPTIONS_DIALOG_MODE, MODE_GET_INSPIRE_BY_DO);
if (fragment.getArguments() != null) {
fragment.getArguments().putAll(bundle);
} else
fragment.setArguments(bundle);
}
//This is how I managed to Check if the fragment exist and update the arguments.
public static void showDoInspireDialog(FragmentManager fragmentManager, long doId, DoOptionsFragment.DoOptionCallBack callBack) {
DoOptionsFragment doOptionsFragment = (DoOptionsFragment) fragmentManager.findFragmentByTag("do_options_fragment");
if (doOptionsFragment == null) {
doOptionsFragment = DoOptionsFragment.getInspiredByDoInstance(doId, callBack);
fragmentManager.beginTransaction()
.add(doOptionsFragment, "do_options_fragment")
.commit();
} else {
doOptionsFragment.setCallBack(callBack);
setInspireByDoArguments(doOptionsFragment, doId);
doOptionsFragment.showInspireByDoDialog(doId);
}
}
public static DoOptionsFragment getInspiredByDoInstance(long doId, DoOptionsFragment.DoOptionCallBack callBack) {
DoOptionsFragment doOptionsFragment = new DoOptionsFragment();
setInspireByDoArguments(doOptionsFragment, doId);
doOptionsFragment.setCallBack(callBack);
return doOptionsFragment;
}