我们必须实现与您最近描述的应用程序完全相同的行为。应用程序的屏幕和整体流程已经定义好了,所以我们必须坚持使用它(这是一个iOS应用程序的克隆.)。幸运的是,我们成功地摆脱了屏幕上的后退按钮:)
我们使用TabActivity、FragmentActivity(对片段使用支持库)和片段的混合方式攻击解决方案。在回顾中,我很确定这不是最好的架构决策,但我们成功地让它发挥作用。如果我不得不再做一次,我可能会尝试做一个更基于活动的解决方案(没有片段),或者尝试并且只有一个选项卡的活动,让所有剩下的都是视图(我发现它比整个活动更可重用)。
因此,要求在每个选项卡中都有一些选项卡和可嵌套的屏幕:tab 1
screen 1 -> screen 2 -> screen 3
tab 2
screen 4
tab 3
screen 5 -> 6
等等.。
例如:用户在选项卡1中启动,从屏幕1导航到屏幕2,然后导航到屏幕3,然后切换到选项卡3,从屏幕4导航到6;如果切换回选项卡1,他应该再次看到屏幕3,如果他按回屏幕,他应该返回到屏幕2;再次回到屏幕1;切换到选项卡3,他又在屏幕6。
应用程序中的主要活动是MainTabActivity,它扩展了TabActivity。每个选项卡都与一个活动相关联,比如ActivityInTab1、2和3。然后每个屏幕都是一个片段:MainTabActivity
ActivityInTab1
Fragment1 -> Fragment2 -> Fragment3
ActivityInTab2
Fragment4
ActivityInTab3
Fragment5 -> Fragment6
每个ActivityInTab一次只保存一个片段,并且知道如何将一个片段替换为另一个片段(与ActvityGroup几乎相同)。最酷的是,通过这种方式可以很容易地将每个标签的背板分开。
每个ActivityInTab的功能是完全相同的:知道如何从一个片段导航到另一个片段并维护一个后台堆栈,因此我们将其放入一个基类中。让我们简单地称之为ActivityInTab:abstract class ActivityInTab extends FragmentActivity { // FragmentActivity is just Activity for the support library.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_in_tab);
}
/**
* Navigates to a new fragment, which is added in the fragment container
* view.
*
* @param newFragment
*/
protected void navigateTo(Fragment newFragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, newFragment);
// Add this transaction to the back stack, so when the user presses back,
// it rollbacks.
ft.addToBackStack(null);
ft.commit();
}}
Active_in_tab.xml就是这样的:<?xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:isScrollContainer="true">
如您所见,每个选项卡的视图布局是相同的。这是因为它只是一个名为内容的FrameLayout,可以保存每个片段。这些片段是有每个屏幕视图的片段。
仅为了增加积分,我们还添加了一些小代码,以便在用户按回并且没有更多的片段可返回时显示一个确认对话框:// In ActivityInTab.java...@Overridepublic void onBackPressed() {
FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() > 0) {
// If there are back-stack entries, leave the FragmentActivity
// implementation take care of them.
super.onBackPressed();
} else {
// Otherwise, ask user if he wants to leave :)
showExitDialog();
}}
基本上就是这样的安排。正如您所看到的,每个FragmentActivity(或者仅仅是Android>3中的简单活动)都使用它自己的FragmentManager来处理所有的后台堆叠。
像ActivityInTable 1这样的活动非常简单,它只显示它的第一个片段(即屏幕):public class ActivityInTab1 extends ActivityInTab {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
navigateTo(new Fragment1());
}}
然后,如果一个碎片需要导航到另一个片段,它必须做一些讨厌的铸造.但也没那么糟// In Fragment1.java for example...// Need to navigate to Fragment2.((ActivityIntab) getActivity()).navigateTo(new Fragment2());
差不多就是这样了。我很确定这不是一个非常规范的解决方案(而且大多数情况下肯定不是很好),所以我想问经验丰富的Android开发人员如何更好地实现这一功能,如果这不是Android中的“它是如何做到的”,我将非常感谢您能向我介绍一些链接或材料来解释哪些是这个Android解决这个问题的方法(选项卡、选项卡中的嵌套屏幕等等)。请随意在评论中撕开这个答案:)
这个解决方案不太好的一个标志是,最近我不得不在应用程序中添加一些导航功能。一些奇怪的按钮应该将用户从一个选项卡带到另一个选项卡中,然后进入嵌套的屏幕。用编程的方式做这件事很痛苦,因为谁知道谁有问题,以及处理片段和活动何时实际实例化和初始化。我认为如果那些屏幕和标签都只是视图,那就容易多了。
最后,如果您需要生存的方向变化,重要的是,您的片段是创建使用setArguments/getArguments。如果在片段的构造函数中设置实例变量,就会失败。但幸运的是,这真的很容易修复:只需将所有内容保存在构造函数中的setArguments中,然后用onCreate中的getArguments检索这些东西来使用它们。