Fragment 生命周期

https://www.jianshu.com/p/52daa5ff5130

Fragment 可以作为 Activity 界面的组成部分,而且 Fragment 有自己的生命周期并能进行事件处理,我们像处理 View 一样动态的添加、移除某个 Fragment

静态 Fragment

这是使用 Fragment 最简单的方式,把 Fragment 当成普通的控件,直接写在 Activity 的布局文件中;继承 Fragment,重写 onCreateView 决定 Fragment 的布局

动态 Fragment

val fm: FragmentManager = supportFragmentManager(); //Fragment里面需要调用getChildFragmentManager
val transaction = fm.beginTransaction()
transaction.commit()

Fragment 家族常用 API

  • android.app.Fragment 主要用于定义 Fragment
  • android.app.FragmentManager 主要用于管理 Fragment
  • android.app.FragmentTransaction 保证一系列 Fragment 操作的原子性

FragmentTransaction 相关方法

  • 开启事务:FragmentTransaction transaction = fm.beginTransatcion()
  • 添加 Fragment:transaction.add()
  • 移除 Fragment:transaction.remove()
  • 替换 Fragment,实际上就是remove()然后add():transaction.replace()
  • 隐藏 Fragment,仅仅是设为不可见,并不会销毁:transaction.hide()
  • 显示 Fragment:transaction.show()
  • 销毁 UI 视图,和 remove 不同,此时 fragment 的状态依然由 FragmentManager 维护:detach()
  • 重建 UI 视图,附加到 UI 上并显示:attach()
  • 提交一个事务:transatcion.commit()

Detach 和 Attach 后 Fragment 对应的回调

switch(msg.what) {
    case1:
        fragmentTransaction=fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.framelayout,blankFragmentOne);
        fragmentTransaction.commit();
        break;
    case 2:
        fragmentTransaction=fragmentManager.beginTransaction();
        fragmentTransaction.detach(blankFragmentOne);
        fragmentTransaction.commit();
        break;
    case 3:
        fragmentTransaction=fragmentManager.beginTransaction();
        fragmentTransaction.attach(blankFragmentOne);
        fragmentTransaction.commit();
        break;
}

//09:46:12.489 26270-26270/com.example.application E/parachute: onAttach 1
//09:46:12.489 26270-26270/com.example.application E/parachute: onCreate 1
//09:46:12.490 26270-26270/com.example.application E/parachute: onCreateView 1
//09:46:12.515 26270-26270/com.example.application E/parachute: onActivityCreated 1
//09:46:12.515 26270-26270/com.example.application E/parachute: onStart 1
//09:46:12.515 26270-26270/com.example.application E/parachute: onResume 1

//09:46:14.488 26270-26270/com.example.application E/parachute: onPause 1
//09:46:14.489 26270-26270/com.example.application E/parachute: onStop 1
//09:46:14.490 26270-26270/com.example.application E/parachute: onDestroyView 1

//09:46:16.490 26270-26270/com.example.application E/parachute: onCreateView 1
//09:46:16.495 26270-26270/com.example.application E/parachute: onActivityCreated 1
//09:46:16.496 26270-26270/com.example.application E/parachute: onStart 1
//09:46:16.496 26270-26270/com.example.application E/parachute: onResume 1

Add 和 Remove 后 Fragment 对应的回调

switch(msg.what) {
    case1:
        fragmentTransaction=fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.framelayout,blankFragmentOne);
        fragmentTransaction.commit();
        break;
    case 2:
        fragmentTransaction=fragmentManager.beginTransaction();
        fragmentTransaction.remove(blankFragmentOne);
        fragmentTransaction.commit();
        break;
    case 3:
        fragmentTransaction=fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.framelayout,blankFragmentOne);
        fragmentTransaction.commit();
        break;
}

//09:48:35.027 28354-28354/com.example.application E/parachute: onAttach 1
//09:48:35.027 28354-28354/com.example.application E/parachute: onCreate 1
//09:48:35.028 28354-28354/com.example.application E/parachute: onCreateView 1
//09:48:35.035 28354-28354/com.example.application E/parachute: onActivityCreated 1
//09:48:35.035 28354-28354/com.example.application E/parachute: onStart 
//09:48:35.035 28354-28354/com.example.application E/parachute: onResume 1

//09:48:37.027 28354-28354/com.example.application E/parachute: onPause 1
//09:48:37.027 28354-28354/com.example.application E/parachute: onStop 1
//09:48:37.028 28354-28354/com.example.application E/parachute: onDestroyView 1
//09:48:37.030 28354-28354/com.example.application E/parachute: onDestroy 1
//09:48:37.031 28354-28354/com.example.application E/parachute: onDetach 1

//09:48:39.028 28354-28354/com.example.application E/parachute: onAttach 1
//09:48:39.028 28354-28354/com.example.application E/parachute: onCreate 1
//09:48:39.028 28354-28354/com.example.application E/parachute: onCreateView 1
//09:48:39.040 28354-28354/com.example.application E/parachute: onActivityCreated 1
//09:48:39.040 28354-28354/com.example.application E/parachute: onStart 1
//09:48:39.040 28354-28354/com.example.application E/parachute: onResume 1

hide 和 show 只会触发 onHiddenChanged 回调

FragmentTransaction.addToBackStack(String),把 Transaction 添加到回退栈,这样按返回键时,会执行 popBackStack 将 Transaction 从回退栈中移除,并执行 Transaction 的反向操作,另外,加到回退栈中的 remove 只是只是执行了 detach 操作,不会执行 onDestory 和 onDetach

That's how Fragments on the back stack work: the Fragment's view is destroyed, but the Fragment itself is not destroyed - they are kept in the CREATED state until you hit the back button and return to the Fragment (after which onCreateView() will be called again and you'll move back up to RESUMED).

You have to null out your references to the views in onDestroyView as that's the sign that the view is no longer being used by the Fragment system and it can be safely garbage collected if it wasn't for your continued reference to the View.

Fragment 与 Activity 通信

  • 如果 Activity 中持有 Fragment 引用,可以通过引用直接访问所有 Fragment 的 public 方法
  • 如果 Activity 中未持有 Fragment 引用,每个 Fragment 都有一个唯一的 TAG 或者 ID,可以通过 FragmentManager.findFragmentByTag 或者 FragmentManager.findFragmentById 获得任何 Fragment 实例
  • 在 Fragment 中可以通过 getActivity 得到当前绑定的 Activity 的实例,然后进行操作
<fragment
    android:id="@+id/aaa"
    android:tag="bbb"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:name="cn.example.bjwangzihan.myapplication.MyFragment"/>
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragment1);
fragmentTransaction.commit();
FragmentTransaction fragmentTransaction2 = fragmentManager.beginTransaction();
fragmentTransaction2.add(fragment1,"bbb");
fragmentTransaction2.commit();

add 的时候需要附带 TAG 信息,XML 文件中可以声明 id 和 tag 信息

Fragment 注意事项

获取 Fragment 一定要通过 FragmentManager,可以用 findFragmentWithTag 或者 getFragments 来得到特定或者所有 Fragment,如果没有获取到 Fragment 实例再去创建,否则销毁重建的情况下调用 getContext 时会报 mHost 空指针异常

如果是通过 ViewPager 来间接控制 Fragment 更要注意,传给 FragmentPagerAdapter 的Fragment 实例一定要和 FragmentManager 中的一致,如果 FragmentManager 中没有再去创建

Fragment 子类的构造函数务必要保证有无参构造函数,否则在 restore 时出现"androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment : could not find Fragment constructor",具体参考下面的Fragment实例化源码:

Activity 应该通过 setArguments 向 Fragment 传递数据,在横竖屏切换时,系统会调用默认构造方法来创建 Fragment,但会恢复 arguments

public class FramentTest2Activity extends ActionBarActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout. activity_main);
    if (savedInstanceState == null) {
      getSupportFragmentManager().beginTransaction().
                  add(R.id. container, TestFragment.newInstance("param")).commit();
    }
  }

  public static class TestFragment extends Fragment {
    private static final String ARG = "arg";
    public TestFragment() {
      Log. i("INFO", "TestFragment non-parameter constructor" );
    }
    public static Fragment newInstance(String arg){
      TestFragment fragment = new TestFragment();
      Bundle bundle = new Bundle();
      bundle.putString( ARG, arg);
      fragment.setArguments(bundle);
      return fragment;
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View rootView = inflater.inflate(R.layout. fragment_main, container, false);
      TextView tv = (TextView) rootView.findViewById(R.id. tv);
      tv.setText(getArguments().getString( ARG));
      return rootView;
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little-sparrow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值