欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Activity之Fragment详解和回退

程序员文章站 2022-07-15 10:46:44
...

目录

 

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 的布局文件中声明片段,将其作为 <fragment> 元素插入您的 Activity 布局,或者通过将其添加到某个现有的 ViewGroup,利用应用代码将其插入布局;

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

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

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

2.Fragment的生命周期?

Activity之Fragment详解和回退

3.Fragment添加方式?

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment android:name="com.example.news.ArticleListFragment"
            android:id="@+id/list"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
    <fragment android:name="com.example.news.ArticleReaderFragment"
            android:id="@+id/viewer"
            android:layout_weight="2"
            android:layout_width="0dp"
            android:layout_height="match_parent" />
</LinearLayout>

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<Fragment> 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详解和回退

图中红色部分为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