Fragment的回退栈 与activity的通信 复用 以及两种适配器的区别
阅读原文时间:2021年04月20日阅读:1

Fragment的回退栈

一、什么是回退栈

Activity切换时,相信大家都知道是通过栈的形式,不断压栈出栈,在Fragment的时候,如果你不是手动开启回退栈,它是直接销毁再重建,但如果将Fragment任务添加到回退栈,情况就会不一样了,它就有了类似Activity的栈管理方式。

二、回退栈的使用(fragment跳转的封装)

    public void startToFragment(Context context, int container, Fragment newFragment) {
        FragmentManager manager = getFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace(container, newFragment);
        transaction.addToBackStack(context.getClass().getName());
        transaction.commit();
    }

1.fragment1 --> fragment2

       Fragment2 fragment2 = new Fragment2 ();
       startToFragment(getActivity(), R.id.layout_container, fragment2 );

2.fragment2 --> fragment1

getActivity().getFragmentManager().popBackStack();

3.fragment2 --> fragment3

      Fragment3 fragment3 = new Fragment3 ();
      startToFragment(getActivity(), R.id.layout_container, fragment3 );

4.fragment3 --> fragment1

   //回退栈中某个Fragment之上的所有Fragment
   FragmentManager fragmentManager = getFragmentManager();
   fragmentManager.popBackStackImmediate(
   MainActivity.class.getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);

与activity的通信

通常,Fragment 与 Activity 通信存在三种情形:

  • Activity 操作内嵌的 Fragment

  • Fragment 操作宿主 Activity

  • Fragment 操作同属 Activity中的其他 Fragment

在Android中我们可以通过以下几种方式优雅地实现Activity和fragment之间的通信:

  • Handler

  • 广播

  • EventBus

  • 接口回调

  • Bundle和setArguments(bundle)

Handler

public class MainActivity extends FragmentActivity{ 
      //声明一个Handler 
      public Handler mHandler = new Handler(){       
          @Override
           public void handleMessage(Message msg) { 
                super.handleMessage(msg);
                 //相应的逻辑处理代码
           }
     }

   } 
    public class MainFragment extends Fragment{ 
          //保存Activity传递的handler
           private Handler mHandler;
           @Override
           public void onAttach(Activity activity) { 
                super.onAttach(activity);

                if(activity instance MainActivity){ 
                      mHandler =  ((MainActivity)activity).mHandler; 
                }
           }

         }

这种方式的缺点:

  • Fragment对具体的Activity存在耦合,不利于Fragment复用

  • 不利于维护,若想删除相应的Activity,Fragment也得改动

  • 没法获取Activity的返回数据

所以一般不建议使用这种方法。

广播

在 Activity 中注册广播接收器,在 Fragment中发送广播:

private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(ACTION_NAME)) {
                String msg = intent.getStringExtra("msg");
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        }
    };
    public void registerBoradcastReceiver() {
        IntentFilter myIntentFilter = new IntentFilter();
        myIntentFilter.addAction(ACTION_NAME);
        registerReceiver(mBroadcastReceiver, myIntentFilter);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mBroadcastReceiver);
  }

EventBus

  • MainActivity

    //注册订阅者
    EventBus.getDefault().register(this);
    //定义接收信息的方法
    @Subscribe
    public void onEventMainThread(UserEvent event) {
    btn.setText(event.getUserName());
    service_tv.setText(event.getUserName());
    }

  • Fragment发送信息

    UserEvent event=new UserEvent();
    EventBus.getDefault().post(event);

接口回调

  • 在 Fragment 中定义一个接口

  • 调用接口中的抽象方法

  • 在 Activity 中实现接口,并具体实现接口中的方法,完成通信

Bundle和setArguments(bundle)

  • 初始化Fragment实例并setArguments:

    DiscoverFragment discoverFragment = new DiscoverFragment();
    Bundle bundle = new Bundle();
    bundle.putString("email", email);
    discoverFragment.setArguments(bundle);

  • 在Fragment中拿到Arguments:

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_discover, null);
    Bundle bundle = getArguments();
    //这里就拿到了之前传递的参数
    email = bundle.getString("email");

      return view;

    }

Fragment的复用

一、为什么要复用?

Activity 在重建的时候会恢复其包含的 FragmentManager ,FragmentManager 又会恢复其管理的 Fragment ,同理 Fragment 也会恢复其包含的 FragmentManager,层层递进,直到全部恢复

二、复用会带来哪些好处?

避免显示错乱
避免重复添加
避免多余的内存占用
优化界面启动速度等

Fragment适配器的区别

一、FragmentPagerAdapter

使用FragmentPagerAdapter 时,Fragment对象会一直存留在内存中,所以当有大量的显示页时,就不适合用FragmentPagerAdapter了,FragmentPagerAdapter 适用于只有少数的page情况,像选项卡。

二、FragmentStatePagerAdapter

这个时候你可以考虑使用FragmentStatePagerAdapter ,当使用FragmentStatePagerAdapter 时,如果Fragment不显示,那么Fragment对象会被销毁,(滑过后会保存当前界面,以及下一个界面和上一个界面(如果有),最多保存3个,其他会被销毁掉)
但在回调onDestroy()方法之前会回调onSaveInstanceState(Bundle outState)方法来保存Fragment的状态,下次Fragment显示时通过onCreate(Bundle savedInstanceState)把存储的状态值取出来,FragmentStatePagerAdapter 比较适合页面比较多的情况,像一个页面的ListView 。