Android - 我需要一些关于片段与活动和视图的说明


Answers

  1. 片段是活动的一部分,它为该活动贡献了自己的用户界面。 片段可以被认为是一个子活动。 用户与之交互的完整屏幕称为活动。 活动可以包含多个片段。片段大多是活动的子部分。

  2. 根据屏幕大小,活动可能包含0或多个片段。 片段可以在多个活动中重复使用,因此它在活动中充当可重用组件。

  3. 一个片段不能独立存在。 它应该永远是活动的一部分。 活动可以在任何片段中存在。

Question

在Android API 11+中,Google发布了一个名为Fragment的新类。

在视频中,Google建议尽可能(链接1,链接2),我们应该使用片段而不是活动,但他们没有解释原因。

碎片的目的和它们的一些可能的用途是什么(除了可以通过简单的视图/布局轻松实现的一些UI示例之外)?

我的问题是关于碎片:

  1. 什么是使用片段的目的?
  2. 与使用活动/视图/布局相比,使用片段有什么优点和缺点?

奖金问题:

  1. 你可以给一些片段真正有趣的用途吗? 谷歌没有在他们的视频中提到的东西?
  2. 片段与包含它们的活动之间进行通信的最佳方式是什么?
  3. 当使用碎片时,要记住什么是最重要的事情? 你的经验提示和警告?



片段是应用程序的用户界面或行为的一部分,可以放置在一个活动中,以启用更模块化的活动设计。 如果我们说一个片段是一种子活动,那不会是错误的。

以下是有关片段的重要观点:

  1. 片段拥有自己的布局和自己的行为以及自己的生命周期回调。

  2. 活动正在运行时,您可以在活动中添加或移除碎片。

  3. 您可以在单个活动中组合多个片段来构建多窗格用户界面。

  4. 一个片段可以用于多个活动。

  5. 片段生命周期与其宿主活动的生命周期密切相关。

  6. 当活动暂停时,活动中可用的所有片段也将停止。

  7. 片段可以实现没有用户界面组件的行为。

  8. 片段被添加到Android 3 (Honeycomb)中的API API版本11中。

欲了解更多详情,请访问官方网站Fragments




碎片在某些情况下特别有用,例如我们想要在所有页面中保留导航抽屉的地方。 你可以用你想要的任何片段膨胀一个框架布局,并仍然可以访问导航抽屉。

如果您使用过一项活动,您将不得不将抽屉放在所有导致冗余代码的活动中。 这是片段的一个有趣用途。

我是Android的新手,仍然认为一个片段是有用的。




一个片段存在于一个活动中。

一项活动依靠自己。




片段表示活动中的行为或用户界面的一部分。 您可以在单个活动中组合多个片段来构建多窗格用户界面,并在多个活动中重用片段。 您可以将片段视为活动的模块化部分,该活动有其自己的生命周期,接收自己的输入事件以及可以在活动运行时添加或删除的活动。

  • 您可以独立操作每个片段,例如添加或删除它们。 当您执行这样的片段事务时,您还可以将其添加到由活动管理的后端堆栈中 - 活动中的每个后端堆栈条目都是发生的片段事务的记录。 后退堆栈允许用户通过按下后退按钮来反转片段事务(向后导航)。

  • 将片段作为活动布局的一部分添加时,它位于活动视图层次结构内的ViewGroup中,片段定义其自己的视图布局。 您可以通过将活动布局文件中的片段作为元素或通过将应用程序代码添加到现有ViewGroup中,从而将片段插入到活动布局中。 但是,片段不需要成为活动布局的一部分; 你也可以使用一个没有自己UI的片段作为活动的隐形工作者。

  • 例如:如果您要使用不带Fragments的NavigationDrawer,那么最好将NavigationDrawer实例保存在单个Activity中,并且通过从NavigationDrawer中的项目中进行选择来导航应用程序时,那么所启动的每个活动都不应该实现NavigationDrawer,而应该实现后退按钮以导航回到实现NavigationDrawer的“Main”/ single Activity。

    注意:如果您确实想要在多个活动中实现NavigationDrawer,则必须在每个要显示它的活动中重新创建一个NavigationDrawer的新实例。

    我想这与使用Fragments相比是一个缺点,而如果你使用了一个片段,你将不需要很多抽屉实例,你只需要一个。

    抽屉与片段而不是活动

    如果您在Fragments中使用NavigationDrawer,则抽屉应该在单个Activity中实现,并且每个抽屉项目被选中时,其内容将显示在他们各自的Fragments中。

  • 在片段与其活动之间进行通信:要允许片段与其活动进行通信,可以在Fragment类中定义一个接口并在Activity中实现它。片段捕获onAttach()生命周期方法期间的接口实现,然后调用接口方法以便与活动进行通信。

    public class YourFragment extends ListFragment {
    OnSelectedListener mCallback;
    
    // Container Activity must implement this interface
    public interface OnSelectedListener {
        public void onItemSelected(int position);
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.your_view, container, false);
    }
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnSelectedListener");
        }
    }
    
    }...
    

现在片段可以通过使用OnSelectedListener接口的mCallback实例调用onItemSelected()方法(或接口中的其他方法)来将消息传递给活动。

public static class MainActivity extends Activity
        implements YourFragment.OnSelectedListener{
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
    }

    public void onItemSelected(int position) {
        // The user selected the headline of an article from the YourFragment
        // Do something here to display that article

        YourFragment yourFrag = (YourFragment)
                getSupportFragmentManager().findFragmentById(R.id.your_fragment);

        if (yourFrag != null) {
            // If your frag is available, we're in two-pane layout...

            // Call a method in the YourFragment to update its content
            yourFrag.updateView(position);
        } else {
            // Otherwise, we're in the one-pane layout and must swap frags...

            // Create fragment and give it an argument for the selected item
            YourFragment newFragment = new YourFragment();
            Bundle args = new Bundle();
            args.putInt(YourFragment.ARG_POSITION, position);
            newFragment.setArguments(args);

            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);

            // Commit the transaction
            transaction.commit();
        }
    }
}