如何管理片段像ActivityGroup管理器Activity

时间:2013-06-03 03:53:13

标签: android

我们知道,不推荐使用ActivityGroup。我正在尝试重新配置代码。

此代码使用ActivityGroup:

public void lauchContentActivity(Intnet intent) {
    View view = getLocationActivityManager().startActivity(
            intent.getComponent().getShortClassName(),
            intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP))
            .getDecorView();
    setContentView(view);
}

因此,我可以将任何活动显示为可见,并保存隐藏的活动实例状态。

但FragmentManager只有一个backstack,并且不能将片段带到前面,期望按下Back按钮。

如何管理像ActivityGroup管理器一样的片段活动?

2 个答案:

答案 0 :(得分:2)

这个答案的可行性取决于你想通过不同的活动完成什么。我遇到了类似的问题,我使用Fragment来解决它。想象一下,你的任务有一个Activity,它有不同的方面。然后,您可以轻松地使用Activity收集并保留每个Fragment所需的数据,或者为您的业务逻辑提供信息,而Fragment每个人都可以满足任务的不同方面。我强烈推荐这一点,FragmentFragmentManager应该替换已弃用的ActivityGroup。以下是有关此事的一些文件:

现在,使用Fragment与使用Activity略有不同,但不是很多。基本上,您将Fragment声明为任何其他对象。要显示您将使用的Fragment

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
YourFragment yourFragment = new YourFragment();
fragmentTransaction.replace(R.id.containerID, yourFragment);
fragmentTransaction.addToBackStack();
fragmentTransaction.commit();

您可以使用ADK下载的文档还包含大量使用Fragment的示例。我相信如果你想获得一些高质量的代码片段,这是一个好的开始!

答案 1 :(得分:2)

我实现了片段标签,在添加和删除片段时,我很难实现和理解片段层次结构。

作为管理fragments的问题,它取决于您的要求, this示例详细说明了您的片段层次结构&在HashMap的帮助下管理片段的方法。

下面的课将解释你的片段行为。 (该样本中的课程)

AppMainTabActivity.java

public class AppMainTabActivity extends FragmentActivity {
    /* Your Tab host */
    private TabHost mTabHost;

    /* A HashMap of stacks, where we use tab identifier as keys.. */
    private HashMap<String, Stack<Fragment>> mStacks;

    /* Save current tabs identifier in this.. */
    private String mCurrentTab;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.app_main_tab_fragment_layout);

        /*
         * Navigation stacks for each tab gets created.. tab identifier is used
         * as key to get respective stack for each tab
         */
        mStacks = new HashMap<String, Stack<Fragment>>();
        mStacks.put(AppConstants.TAB_A, new Stack<Fragment>());
        mStacks.put(AppConstants.TAB_B, new Stack<Fragment>());
        mStacks.put(AppConstants.TAB_C, new Stack<Fragment>());

        mTabHost = (TabHost) findViewById(android.R.id.tabhost);
        mTabHost.setOnTabChangedListener(listener);
        mTabHost.setup();

        initializeTabs();
    }

    private View createTabView(final int id) {
        View view = LayoutInflater.from(this).inflate(R.layout.tabs_icon, null);
        ImageView imageView = (ImageView) view.findViewById(R.id.tab_icon);
        imageView.setImageDrawable(getResources().getDrawable(id));
        return view;
    }

    public void initializeTabs() {
        /* Setup your tab icons and content views.. Nothing special in this.. */
        TabHost.TabSpec spec = mTabHost.newTabSpec(AppConstants.TAB_A);
        mTabHost.setCurrentTab(-3);
        spec.setContent(new TabHost.TabContentFactory() {
            public View createTabContent(String tag) {
                return findViewById(R.id.realtabcontent);
            }
        });

        spec.setIndicator(createTabView(R.drawable.toolkittabicon));
        mTabHost.addTab(spec);

        spec = mTabHost.newTabSpec(AppConstants.TAB_B);
        spec.setContent(new TabHost.TabContentFactory() {
            public View createTabContent(String tag) {
                return findViewById(R.id.realtabcontent);
            }
        });
        spec.setIndicator(createTabView(R.drawable.followtabicon));
        mTabHost.addTab(spec);

        spec = mTabHost.newTabSpec(AppConstants.TAB_C);
        spec.setContent(new TabHost.TabContentFactory() {
            public View createTabContent(String tag) {
                return findViewById(R.id.realtabcontent);
            }
        });
        spec.setIndicator(createTabView(R.drawable.myhuddletabicion));
        mTabHost.addTab(spec);
    }

    /* Comes here when user switch tab, or we do programmatically */
    TabHost.OnTabChangeListener listener = new TabHost.OnTabChangeListener() {
        public void onTabChanged(String tabId) {
            /* Set current tab.. */
            mCurrentTab = tabId;

            if (mStacks.get(tabId).size() == 0) {
                /*
                 * First time this tab is selected. So add first fragment of
                 * that tab. Dont need animation, so that argument is false. We
                 * are adding a new fragment which is not present in stack. So
                 * add to stack is true.
                 */
                if (tabId.equals(AppConstants.TAB_A)) {
                    pushFragments(tabId, new ToolKitFragment(), false, true);
                } else if (tabId.equals(AppConstants.TAB_B)) {
                    pushFragments(tabId, new FollowFragment(), false, true);
                } else if (tabId.equals(AppConstants.TAB_C)) {
                    pushFragments(tabId, new HuddleFragment(), false, true);
                }
            } else {
                /*
                 * We are switching tabs, and target tab is already has atleast
                 * one fragment. No need of animation, no need of stack pushing.
                 * Just show the target fragment
                 */
                pushFragments(tabId, mStacks.get(tabId).lastElement(), false,
                        false);
            }
        }
    };

    /*
     * Might be useful if we want to switch tab programmatically, from inside
     * any of the fragment.
     */
    public void setCurrentTab(int val) {
        mTabHost.setCurrentTab(val);
    }

    /*
     * To add fragment to a tab. tag -> Tab identifier fragment -> Fragment to
     * show, in tab identified by tag shouldAnimate -> should animate
     * transaction. false when we switch tabs, or adding first fragment to a tab
     * true when when we are pushing more fragment into navigation stack.
     * shouldAdd -> Should add to fragment navigation stack (mStacks.get(tag)).
     * false when we are switching tabs (except for the first time) true in all
     * other cases.
     */
    public void pushFragments(String tag, Fragment fragment,
            boolean shouldAnimate, boolean shouldAdd) {
        if (shouldAdd)
            mStacks.get(tag).push(fragment);
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        if (shouldAnimate)
            ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
        ft.replace(R.id.realtabcontent, fragment);
        ft.commit();
    }

    public void popFragments() {
        /*
         * Select the second last fragment in current tab's stack.. which will
         * be shown after the fragment transaction given below
         */
        Fragment fragment = mStacks.get(mCurrentTab).elementAt(
                mStacks.get(mCurrentTab).size() - 2);

        /* pop current fragment from stack.. */
        mStacks.get(mCurrentTab).pop();

        /*
         * We have the target fragment in hand.. Just show it.. Show a standard
         * navigation animation
         */
        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction ft = manager.beginTransaction();
        ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
        ft.replace(R.id.realtabcontent, fragment);
        ft.commit();
    }

    @Override
    public void onBackPressed() {
        if (((BaseFragment) mStacks.get(mCurrentTab).lastElement())
                .onBackPressed() == false) {
            Log.d("######", "on back press");
            /*
             * top fragment in current tab doesn't handles back press, we can do
             * our thing, which is
             * 
             * if current tab has only one fragment in stack, ie first fragment
             * is showing for this tab. finish the activity else pop to previous
             * fragment in stack for the same tab
             */
            if (mStacks.get(mCurrentTab).size() == 1) {
                super.onBackPressed(); // or call finish..
            } else {
                popFragments();
            }
        } else {
            // do nothing.. fragment already handled back button press.
        }
    }

    /*
     * Imagine if you wanted to get an image selected using ImagePicker intent
     * to the fragment. Ofcourse I could have created a public function in that
     * fragment, and called it from the activity. But couldn't resist myself.
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (mStacks.get(mCurrentTab).size() == 0) {
            return;
        }

        /* Now current fragment on screen gets onActivityResult callback.. */
        mStacks.get(mCurrentTab).lastElement()
                .onActivityResult(requestCode, resultCode, data);
    }
}

但是,如果您有子片段,那么它将在该样本中无法处理的背面创建问题,解决方案@您必须覆盖onDetach()方法并管理子片段检查下面的代码片段

@Override
    public void onDetach() {
        super.onDetach();
         try {
                Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
                childFragmentManager.setAccessible(true);
                childFragmentManager.set(this, null);

            } catch (NoSuchFieldException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
    }

另外请参阅开发者网站并详细挖掘fragment