Activity之Fragment详解和回退

目录

 

1.Fragment是什么?

2.Fragment的生命周期?

3.Fragment添加方式?

3.1在 Activity 的布局文件内声明片段

3.2通过编程方式将片段添加到某个现有 ViewGroup

4.编程方式动态添加,替换或者修改Fragment

5.实现Fragment回退

5.1定义Fragment返回监听接口,Fragment需要实现此接口

5.2定义BackHandlerHelper帮助类,进行返回事件分发,用于实现Fragment和FragmentActivity返回操作,主要实现将FragmentActivity监听到的返回事件进行分发给Fragment

5.3定义Fragment基类,其他需要监听返回事件类需要继承BackHandledFragment基类

5.4FragmentActivity调用工具方法BackHandlerHelper.handleBackPress(this),将返回事件进行分发

6.Fragment之间的数据交换

6.1Fragment通知数据给Activity

6.2将消息传递给Activity


1.Fragment是什么?

Fragment相当于FragmentActivity界面的一部分,Fragment生命周期直接受宿主 Activity 生命周期的影响;Activity会维护Fragment返回栈,方便通过返回按钮关闭当前显示的Fragment进行回退;您可以通过在 Activity 的布局文件中声明片段,将其作为 元素插入您的 Activity 布局,或者通过将其添加到某个现有的 ViewGroup,利用应用代码将其插入布局;

Fragment 表示 FragmentActivity 中的行为或界面的一部分。您可以在一个 Activity 中组合多个片段,从而构建多窗格界面,并在多个 Activity 中重复使用某个片段。您可以将片段视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除片段(这有点像可以在不同 Activity 中重复使用的“子 Activity”)。

片段必须始终托管在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。例如,当 Activity 暂停时,Activity 的所有片段也会暂停;当 Activity 被销毁时,所有片段也会被销毁。不过,当 Activity 正在运行(处于已恢复生命周期状态)时,您可以独立操纵每个片段,如添加或移除片段。当执行此类片段事务时,您也可将其添加到由 Activity 管理的返回栈 — Activity 中的每个返回栈条目都是一条已发生片段事务的记录。借助返回栈,用户可以通过按返回按钮撤消片段事务(后退)。

当您将片段作为 Activity 布局的一部分添加时,其位于 Activity 视图层次结构的某个 ViewGroup 中,并且片段会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明片段,将其作为 元素插入您的 Activity 布局,或者通过将其添加到某个现有的 ViewGroup,利用应用代码将其插入布局。

2.Fragment的生命周期?

Activity之Fragment详解和回退_第1张图片

3.Fragment添加方式?

3.1在 Activity 的布局文件内声明片段



    
    

3.2通过编程方式将片段添加到某个现有 ViewGroup

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

4.编程方式动态添加,替换或者修改Fragment

//1.创建一个Fragment和transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

//2.添加添加add(),替换replace()Fragment到指定ViewGroup上,或者移除remove()Fragment
transaction.replace(R.id.fragment_container, newFragment);
//3.add()或者replace()以后调用addToBackStack()将事务添加到片段事务返回栈
//非必须调用,
transaction.addToBackStack(null);

//提交事务
transaction.commit();

5.实现Fragment回退

Fragment并没有onBackPressed()方法,假如需要在Fragment监听返回操作需要自己实现返回的回调监听;

5.1定义Fragment返回监听接口,Fragment需要实现此接口

/**
 * 返回接口
 */
public interface FragmentBackHandler {
    boolean onBackPressed();
}

5.2定义BackHandlerHelper帮助类,进行返回事件分发,用于实现Fragment和FragmentActivity返回操作,主要实现将FragmentActivity监听到的返回事件进行分发给Fragment

public class BackHandlerHelper {
    /**
     * 将back事件分发给FragmentManager中管理的子Fragment,如果FragmentManager中的子Fragment没有处理
     * back事件,则调用fragmentManager.popBackStack();执行fragment返回
     *
     * true表示处理返回事件
     * false表示未处理返回事件
     * @param fragmentManager
     * @return
     */
    public static boolean handleBackPress(FragmentManager fragmentManager){
        List fragments = fragmentManager.getFragments();
        if(fragments == null) return false;

        for(int i=fragments.size()-1; i>=0; i--)
        {
            Fragment child = fragments.get(i);
            if(isFragmentBackHandled(child)){
                return true;
            }
        }

        if(fragmentManager.getBackStackEntryCount() > 0){
            fragmentManager.popBackStack();
            return true;
        }

        return false;
    }

    public static boolean handleBackPress(Fragment fragment){
        return handleBackPress(fragment.getChildFragmentManager());
    }

    public static boolean handleBackPress(FragmentActivity fragmentActivity){
        return handleBackPress(fragmentActivity.getSupportFragmentManager());
    }


    /**
     * 判断Fragment是否处理了Back键,处理了返回true
     * @param fragment
     * @return
     */
    public static boolean isFragmentBackHandled(Fragment fragment){
        return fragment !=null
                && fragment.isVisible()
                && fragment.getUserVisibleHint() //for viewpager
                && fragment instanceof FragmentBackHandler
                && ((FragmentBackHandler) fragment).onBackPressed();//调用Fragment返回方法

    }
}

5.3定义Fragment基类,其他需要监听返回事件类需要继承BackHandledFragment基类

/**
 * Fragment基类,自己实现返回事件
 */
public abstract class BackHandledFragment extends Fragment implements FragmentBackHandler {

    @Override
    public boolean onBackPressed() {
        return BackHandlerHelper.handleBackPress(this);
    }
}

Fragment具体实现类继承BackHandledFragment基类,若需要监听返回事件,可以重写onBackPressed方法;

public class FragmentOne extends BackHandledFragment implements View.OnClickListener{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_item,container,false);
        TextView mTextView = (TextView) view.findViewById(R.id.tv_fragment_content);
        mTextView.setText("FragmentOne");
        Button mButton = (Button) view.findViewById(R.id.btn_toggle_fragment);
        mButton.setOnClickListener(this);
        return view;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_toggle_fragment:
                FragmentTwo ftwo = new FragmentTwo();
                FragmentManager mManager = getFragmentManager();
                FragmentTransaction ft = mManager.beginTransaction();
                ft.addToBackStack(null); //这里将我们的Fragment加入到返回栈
                ft.replace(R.id.fl_fragment_container, ftwo);
                ft.commit();
                break;
        }
    }
}

5.4FragmentActivity调用工具方法BackHandlerHelper.handleBackPress(this),将返回事件进行分发

public class FragmentManagerAcitivty extends AppCompatActivity {

    private Fragment fragmentone;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_main);
        fragmentone = new FragmentOne();
            getSupportFragmentManager().beginTransaction().add(R.id.fl_fragment_container,fragmentone, "one").commit();
    }

    @Override
    public void onBackPressed() {
        if (!BackHandlerHelper.handleBackPress(this)) {
            super.onBackPressed();
        }
    }
}

返回事件分发

Activity之Fragment详解和回退_第2张图片

图中红色部分为BackHandledFragment 或其它实现了 FragmentBackHandler的Fragment。
back事件由下往上传递,当中间有未实现FragmentBackHandler的Fragment作为其它Fragment的容器时,或该Fragment拦截了事件时,其子Fragment无法处理back事件。
有没有一种似曾相识的感觉?其实这和View的事件分发机制是一个道理。

注意:这种方式支持多个Fragment返回,及Fragment嵌套,仅需要在Activity或者Fragment调用onBackPressed()实现返回事件监听和分发;
原理

1)不管是Activity也好,Fragment也好,其中内部包含的Fragment都是通过FragmentManager来管理的。
2)FragmentManager.getFragments()可以获取当前Fragment/Activity中处于活动状态的所有Fragment
3)事件由Activity交给当前Fragment处理,如果Fragment有子Fragment的情况同样可以处理。


6.Fragment之间的数据交换

6.1Fragment通知数据给Activity

要允许 Fragment 与其 Activity 进行通信,可以在 Fragment 类中定义接口并在 Activity 中实现该接口。Fragment 在其 onAttach() 生命周期方法中捕获接口实现,然后可以调用接口方法,以便与 Activity 通信。

以下是 Fragment 到 Activity 通信的示例:

public class HeadlinesFragment extends ListFragment {
        OnHeadlineSelectedListener callback;

        public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener callback) {
            this.callback = callback;
        }

        //这个接口将被Activity或者父Fragment实现
        public interface OnHeadlineSelectedListener {
            public void onArticleSelected(int position);
        }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // 发送事件给主Activity
        callback.onArticleSelected(position);
    }
}

Activity实现Fragment定义OnHeadlineSelectedListener接口,Fragment将获取主Activity通信接口实现,Fragment中callback可以通知数据给Activity ;

 public static class MainActivity extends Activity
            implements HeadlinesFragment.OnHeadlineSelectedListener{
        // ...

        @Override
        public void onAttachFragment(Fragment fragment) {
            if (fragment instanceof HeadlinesFragment) {
                HeadlinesFragment headlinesFragment = (HeadlinesFragment) fragment;
                headlinesFragment.setOnHeadlineSelectedListener(this);
            }
        }
    }

6.2将消息传递给Activity

托管 Activity 可通过使用 findFragmentById() 捕获 Fragment 实例,将消息传递到 Fragment,然后直接调用 Fragment 的公共方法。

例如,假设上方所示的 Activity 可能包含另一个 Fragment,该 Fragment 用于显示由上述回调方法中返回的数据指定的项。在这种情况下,Activity 可以将回调方法中收到的信息传递给显示该项的另一个 Fragment:

public static class MainActivity extends Activity
            implements HeadlinesFragment.OnHeadlineSelectedListener{
        ...
        //在HeadlinesFragment调用onArticleSelected()方法传递数据给Activity
        public void onArticleSelected(int position) {
            //例如用户在列表选择了一篇文章,需要将选择的位置发送给ArticleFragment处理
            ArticleFragment articleFrag = (ArticleFragment)
                    getSupportFragmentManager().findFragmentById(R.id.article_fragment);

            if (articleFrag != null) {
                //调用ArticleFragment方法显示文件
                articleFrag.updateArticleView(position);
            } else {
                //新建ArticleFragment,并将参数传递给ArticleFragment
                ArticleFragment newFragment = new ArticleFragment();
                Bundle args = new Bundle();
                args.putInt(ArticleFragment.ARG_POSITION, position);
                newFragment.setArguments(args);

                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.fragment_container, newFragment);
                transaction.addToBackStack(null);

                transaction.commit();
            }
        }
    }

 

参考:

https://developer.android.google.cn/training/basics/fragments/communicating?hl=zh_cn

https://www.jianshu.com/p/fff1ef649fc0

 

你可能感兴趣的:(Android拓展)