片段:替换片段会导致它在按下后重新实例化
Fragments: Replacing a fragment causes it to reinstantiate on back pressed
我正在使用一种 activity 全片段方法。现在我有一个片段 A,当我转到片段 B 时,我用
将容器中的 A 替换为 B
.replace(R.id.master_fragment_container_above_toolbar, fragment)
.addToBackStack("")
.commit();
如您所见,我已将片段添加到 backStack。但是现在当我在设备上按回时,它会重新实例化片段 A,因此返回需要时间。
还有其他方法吗?我不想使用add()
,如果我向容器中添加多个片段,它会占用大量内存。
简短的回答 - 你的情况没有灵丹妙药。您必须使用 replace()
,它会在返回时重新创建片段的 View
。那是 "by design".
好消息是,您可以采取一些技巧来降低 UX 的戏剧性。
尽可能缓存。如果您从网络加载内容 - 将其写入本地 SQLite 数据库。并从本地存储填充屏幕,同时从服务器刷新数据。
在 onCreateView()
中避免重新创建已经存在的适配器。如果用户从 FragmentB 返回到 FragmentA,FragmentA 将重新创建其 View
。但这并不意味着此时局部变量为空。所以我这样做:
public class FeedFragment extends Fragment {
private FeedAdapter adapter;
......
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = initialize(inflater, container, R.layout.fragment_with_recyclerview);
....
if (adapter == null) {
adapter = new FeedAdapter();
}
RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recyclerView)
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
return rootView;
}
}
这很重要,因为填充 TextView
等操作非常快,您并不真正关心它,而巨大的 ListView
或 RecyclerView
可能会很多更贵;
使用图像缓存和良好的图像加载工具。我推荐来自 Square 的 Picasso。它具有自动内存和磁盘缓存;
尝试从逻辑上解耦您的应用程序。让我们以一个 Gmail 风格的应用程序为例:
它有 NavigationDrawer
,它通过根片段切换用户(即不需要保留导航堆栈)。打开邮件线程后,它会将根片段替换为 MailThread 片段。在那里你可以消费内容。
但是一旦您点击 "Compose email" - 您将重定向到一个单独的 Activity
- 当您从消费内容状态转变为撰写内容状态时(即用户行为的显着变化:新用户场景==新activity).
许多顶级开发人员走得更远,几乎所有内容都有活动。以 Twitter(及其卫星产品)为例。但就个人而言,我更喜欢保持平衡(因为从性能角度来看,打开新 activity 是一项昂贵的操作)。
我正在使用一种 activity 全片段方法。现在我有一个片段 A,当我转到片段 B 时,我用
将容器中的 A 替换为 B.replace(R.id.master_fragment_container_above_toolbar, fragment)
.addToBackStack("")
.commit();
如您所见,我已将片段添加到 backStack。但是现在当我在设备上按回时,它会重新实例化片段 A,因此返回需要时间。
还有其他方法吗?我不想使用add()
,如果我向容器中添加多个片段,它会占用大量内存。
简短的回答 - 你的情况没有灵丹妙药。您必须使用 replace()
,它会在返回时重新创建片段的 View
。那是 "by design".
好消息是,您可以采取一些技巧来降低 UX 的戏剧性。
尽可能缓存。如果您从网络加载内容 - 将其写入本地 SQLite 数据库。并从本地存储填充屏幕,同时从服务器刷新数据。
在
onCreateView()
中避免重新创建已经存在的适配器。如果用户从 FragmentB 返回到 FragmentA,FragmentA 将重新创建其View
。但这并不意味着此时局部变量为空。所以我这样做:public class FeedFragment extends Fragment { private FeedAdapter adapter; ...... @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = initialize(inflater, container, R.layout.fragment_with_recyclerview); .... if (adapter == null) { adapter = new FeedAdapter(); } RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recyclerView) recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); return rootView; } }
这很重要,因为填充
TextView
等操作非常快,您并不真正关心它,而巨大的ListView
或RecyclerView
可能会很多更贵;使用图像缓存和良好的图像加载工具。我推荐来自 Square 的 Picasso。它具有自动内存和磁盘缓存;
尝试从逻辑上解耦您的应用程序。让我们以一个 Gmail 风格的应用程序为例: 它有
NavigationDrawer
,它通过根片段切换用户(即不需要保留导航堆栈)。打开邮件线程后,它会将根片段替换为 MailThread 片段。在那里你可以消费内容。但是一旦您点击 "Compose email" - 您将重定向到一个单独的
Activity
- 当您从消费内容状态转变为撰写内容状态时(即用户行为的显着变化:新用户场景==新activity).许多顶级开发人员走得更远,几乎所有内容都有活动。以 Twitter(及其卫星产品)为例。但就个人而言,我更喜欢保持平衡(因为从性能角度来看,打开新 activity 是一项昂贵的操作)。