文章目录

  • 前言
  • 一、什么是Fragment?
  • 二、Fragment与Activity的区别与优势
    • 1、生命周期不同
    • 2、Fragment的使用优势
  • 三、Fragment的生命周期
  • 四、Fragment的简单使用
    • 1、 静态使用
    • 2、动态使用
  • 五、Fragment的回退栈
  • 六、Fragment的通信
  • 七、Fragment工具类
  • 总结

前言

去年年底的时候需要改一个项目,接触到了fragment。也没有对fragment进行系统的学习,就开始动手改了,边改边学,现在闲下来了,对fragment进行一些总结。


一、什么是Fragment?

Fragment是Android3.0提出来的,之前刚提出来的时候,是不兼容Android3.0以下的版本(话说现在已经没有人使用3.0以下的手机了吧),为了兼容低版本,就出现了v4包下的fragment,网络上对fragment的使用一般都是v4包下fragment,对于app包下的fragment的使用不仅很少,而且都是教程不全,或者坑太多。此文对app包下的fragment做一个详细的讲解。对于fragment,我们可以简单的理解为,是在Activity中的Activity。它可以显示在Activity中,显示出自己的内容。但是fragment是依赖于Activity存在的,不能够自己单独存在,同样的一个Activity中可以有多个fragment,而且一个fragment可以被多个Activity使用,拥有自己的生命周期,我们可以在Activity中动态的进行fragment的添加删除。说到这里,感觉有点像Android中include标签的使用了,但是include只是相当于告诉编译器,这里只是放入了一个布局,去加载这个布局,但是fragment是让编译器去实例化这个fragment。

二、Fragment与Activity的区别与优势

1、生命周期不同

Activity的生命周期:

onCreate()-onStart()-onResume()-onPause()-onStop()-onDestroy()-onRestart()

fragment的生命周期:

onAttach()-onCreate()-onCreateView()-onActivityCreated()-onStart()-onResume()-onPause()- onStop()-onDestroyView()-onDestroy()-onDetach()

通过生命周期可以明显的看出来fragment比activity的生命周期要多,同时一个activity就是一个activity,fragment的意思就是碎片,所谓碎片,就反应出来了fragment比activity灵活,好控制。

2、Fragment的使用优势

  • 模块化:我们不需要把所有代码全部都写在Activity中,而是把代码写在各自的fragmen中,减少了代码的复杂性,后期维护比较简单。
  • 可重性:多个Activity可以重用同一个fragment。
  • 适配性:根据不同手机的尺寸,方向,可以实现不同的布局,使客户的体验性更好。

三、Fragment的生命周期

生命周期前面我门已经看到了,这里具体讲一下各生命周期的区别:
先看张图

对于activity的生命周期想必大家都已经很熟悉了,这里只介绍fragment的生命周期:

onAttach(Activity): 当Fragment与Activity发生关联的时候调用,可以通过getArguments()获取参数,该方法只会调用一次
onCreate():Fragment被创建时调用,该方法只会调用一次
onCreateView(LayoutInflater, ViewGroup, Bundle) 创建fragment布局,必须返回一个View,该View就是Fragment需要显示的界面
onActivityCreated(Bundle) :加载布局结束后调用
onStart():当Fragment可见调用
onResume():当Fragment可见且可交互时调用
onPause():当Fragment不可交互但可见时调用
onStop():当Fragment不可见时调用
onDestroyView() Fragment的布局被移除时调用
onDestroy():销毁Fragment时调用
onDetach() :Fragment和Activity解除关联的时候调用

四、Fragment的简单使用

fragment有两种使用方法,一种是静态使用,一种是动态使用。

1、 静态使用

静态使用就是在布局的xml文件中添加name属性去加载fragment,这种方式有一个缺点,就是在fragment运行的时候,不能够进行删除这个fragment,因此我们一般用动态加载就可以了。

(1):创建布局文件fragment_home.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent">
<Buttonandroid:id="@+id/btn_one"android:text="1111"android:layout_width="wrap_content"android:layout_height="wrap_content">
</Button><Buttonandroid:id="@+id/btn_two"android:text="2222"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button><Buttonandroid:id="@+id/btn_three"android:text="3333"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button><Buttonandroid:id="@+id/btn_four"android:text="4444"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button>
</LinearLayout>

(2):创建一个类BaseFragment继承Fragment,重写onAttach方法:

public class BaseFragment extends Fragment {public String TAG = getClass().getSimpleName();@Overridepublic void onAttach(@NonNull Context context) {super.onAttach(context);}
}

(3):创建一个HomeFragment类,重写onCreateView方法。进行fragment的具体操作,继承上面创建的类BaseFragment(你们也可以直接创建HomeFragment类,重写onAttach方法):

public class HomeFragment extends BaseFragment {public  HomeFragment(){/*对于为什么要使用无参构造函数,是因为当屏幕方向发生变化的时候,会重新构造fragment,会优先调用fragment无参的构造方法,如果参数是通过构造函数传递的,在重新构造fragment时,参数就会丢失。如果要在fragment创建的时候就要传入参数,不建议使用构造函数,可以使用setArguments()方式进行添加,因为如果fragment被系统杀掉再次恢复的时候,能够保留这些数据,后面将会介绍这种方法*/}/*** 加载布局时候调用* @param inflater* @param container* @param savedInstanceState* @return*/@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {// 1. 加载布局,第三个参数必须为`false`,否则会加载两次布局并且抛出异常!!//原因:在fragment内部中,会将布局添加到container中,如果设置为true,就会重复两个添加,报IllegalStateException异常return inflater.inflate(R.layout.fragment_home,container,false);}
}

(3):Acticity对应的布局文件(注意name标签,就是指定Activity加载哪一个fragment):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><fragmentandroid:name="com.example.dhd.fragmentdemo.fragment.HomeFragment"android:id="@+id/fragment"android:layout_width="match_parent"android:layout_height="match_parent"></fragment>
</RelativeLayout>

(4):MainActivity对应代码(网上很多人说使用app包下的fragment继承Activity即可,我试了继承Activity程序会直接崩溃,继承AppCompatActivity或者FragmentActivity才可以成功运行(AppCompatActivity是FragmentActivity的一个子类)。):

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//initView();}
}

运行效果:

2、动态使用

对于动态加载的使用,我在使用的时候因为不仔细,让我自己烦恼了很长时间。
静态加载的布局文件中使用的标签是fragment,而在动态加载中使用的标签是FrameLayout。主要动态加载布局文件不要使用fragment,否则你会和我一样很苦恼为什么报错而且找不到问题所在。
先看一下效果:

刚开始显示的是fragment_home.xml,点击跳转后,显示的是fragment_one.xml

(1)activity_main布局文件:

注意是FrameLayout标签

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:id="@+id/btn_jump"android:text="跳转"android:layout_centerHorizontal="true"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button><FrameLayoutandroid:layout_below="@+id/btn_jump"android:id="@+id/fragment"android:layout_width="match_parent"android:layout_height="200dp"></FrameLayout>
</RelativeLayout>

(2)创建两个fragment布局文件:
fragment_home.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/btn_home"android:text="home"android:layout_width="match_parent"android:layout_height="40dp"></Button>
</RelativeLayout>

fragment_one.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/btn_one"android:text="one"android:layout_width="match_parent"android:layout_height="40dp"></Button>
</RelativeLayout>

(3)创建对应布局文件的fragmentActivity:

BaseFragment

public class BaseFragment extends Fragment {public String TAG = getClass().getSimpleName();@Overridepublic void onAttach(@NonNull Context context) {super.onAttach(context);}
}

HomeFragment

public class HomeFragment extends BaseFragment{public HomeFragment() {}/*** 加载布局时候调用** @param inflater* @param container* @param savedInstanceState* @return*/@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {// 1. 加载布局,第三个参数必须为`false`,否则会加载两次布局并且抛出异常!!return inflater.inflate(R.layout.fragment_home, container, false);}}

OneFragment

public class OneFragment extends BaseFragment {public OneFragment() {}@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_one,container,false);}
}

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private HomeFragment homeFragment;private Button btn_jump;private FragmentManager fragmentManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {showFragment();btn_jump = (Button) findViewById(R.id.btn_jump);btn_jump.setOnClickListener(this);}private void showFragment() {//获取FragmentManager管理对象,使用 getFragmentManager()方法已经过时,并且有错误。fragmentManager = getSupportFragmentManager();//获取FragmentTransaction事物对象,并开启事务FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//创建fragment对象homeFragment = new HomeFragment();//操作fragment,布局ID,fragment对象,还有第三个参数(tag,可写可不写)tag作为fragment的唯一标志,可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("tag")从FragmentManager中查找Fragment对象。fragmentTransaction.add(R.id.fragment, homeFragment);//提交事务fragmentTransaction.commit();}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_jump:OneFragment oneFragment = new OneFragment();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//replace就是替换fragment中原有的fragment,将其替换为oneFragment,最后不要忘记commit,否则会没有效果fragmentTransaction.replace(R.id.fragment,oneFragment).commit();break;}}
}

静态加载和动态加载的使用就是这样了,在项目中一般都是用动态加载的方法,毕竟静态加载的时候是不能删除正在使用的fragment。

补充一下fragmentTransaction的几种使用方法:

  • fragmentTransaction.add() 向Activity中添加一个Fragment
  • transaction.remove() 从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈(回退栈后面会详细说),这个Fragment实例将会被销毁
  • fragmentTransaction.replace() 使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体
  • fragmentTransaction.hide() 隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
  • fragmentTransaction.show() 显示之前隐藏的Fragment
  • detach() 会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护
  • attach() 重建view视图,附加到UI上并显示
  • fragmentTransaction.commit() 提交事务

注意:在add/replace/hide/show以后都要提交事务其效果才会在屏幕上显示出来

提交事务有四种方式:
1.commit():

  • 当你调用commit()的时候, FragmentManger会检查是否已经存储了它自己的状态, 如果已经存在, 就抛出IllegalStateException,同样说明每个事务只能存在一次,如果你再重新重新创建一个事务,再去提交,这个时候是没有问题的。
  • 一旦调用这个方法, 这个commit()并不是立即执行的, 它会被发送到主线程的任务队列当中去, 当主线程准备好执行它的时候执行
  • Activity执行完onSaveInstanceState()方法后不能再执行commit()方法

2.commitAllowingStateLoss():

  • 当你调用commitAllowingStateLoss()的时候, FragmentManger不会检查是否已经存储了它自己的状态, 也就不会抛出IllegalStateException.有效的解决了commit()提交时出现的问题。

3.commitNow():

  • 当你调用commitNow()时,将会立即执行并且只会执行你当前要提交的transaction。
  • 从v24.0.0开始提供了 commitNow()方法,在之前开发者会在commit()调用之后加上 executePendingTransactions()来保证立即执行, 即变异步为同步,但是这样会将所有pending在队列中还有你新提交的transactions都执行了,而commitNow()就避免那些你可能并不想执行的transactions。

4.commitNowAllowingStateLoss():

  • 当你调用commitNowAllowingStateLoss()的时候, FragmentManger不会检查是否已经存储了它自己的状态, 也就不会抛出IllegalStateException,并且会立即执行。

五、Fragment的回退栈

Fragment的回退栈是用来保存每一次Fragment事务发生的变化 如果你将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。官方的说法就是就是你在点击后退键的时候,到底要不要显示上一个fragment.
要把fragment添加到回退栈,需要学会一个方法:

FragmentTransaction.addToBackStack(String)

下面用案列进行演示:
先看一下效果图

我默认第一个Activity打开homeFragment,在输入框内输入111.点击HOME,将HomeFragment覆盖为OneFragment,输入222,点击ONE,将OneFragment覆盖为TwoFragment,点击返回键,返回到OneFragment,可以看到输入框上面还有,再次点击返回键,返回到HomeFragment,输入框有222。这里我们再次点击到最后一个fragment,点击two,跳转到第二个Activity.

文件目录:

下面来看代码:
fragment_home.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/btn_home"android:text="home"android:layout_width="match_parent"android:layout_height="40dp"></Button><EditTextandroid:id="@+id/et_home"android:layout_below="@+id/btn_home"android:layout_width="match_parent"android:layout_height="wrap_content"></EditText>
</RelativeLayout>

activity_main.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><FrameLayoutandroid:id="@+id/fragment"android:layout_width="match_parent"android:layout_height="200dp"></FrameLayout>
</RelativeLayout>

fragment_one.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Buttonandroid:id="@+id/btn_one"android:text="one"android:layout_width="match_parent"android:layout_height="40dp">
</Button><EditTextandroid:id="@+id/et_one"android:layout_below="@+id/btn_one"android:layout_width="match_parent"android:layout_height="wrap_content"></EditText>
</RelativeLayout>

fragment_two.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/btn_two"android:text="two"android:layout_width="match_parent"android:layout_height="40dp"></Button><EditTextandroid:id="@+id/et_two"android:text="已经到最后一个fragment了"android:layout_below="@+id/btn_two"android:layout_width="match_parent"android:layout_height="wrap_content"></EditText>
</RelativeLayout>

activity_second.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".SecondActivity"><TextViewandroid:text="第二个Activity"android:gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"></TextView>
</RelativeLayout>

MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private HomeFragment homeFragment;private FragmentManager fragmentManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {showFragment();}private void showFragment() {//获取FragmentManager管理对象fragmentManager = getSupportFragmentManager();//获取FragmentTransaction事物对象,并开启事务FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//创建fragment对象homeFragment = new HomeFragment();//操作fragment,布局ID,fragment对象fragmentTransaction.add(R.id.fragment, homeFragment);//提交事务fragmentTransaction.commit();}@Overridepublic void onClick(View v) {switch (v.getId()) {}}
}

BaseFragment:

public class BaseFragment extends Fragment {public String TAG = getClass().getSimpleName();@Overridepublic void onAttach(@NonNull Context context) {super.onAttach(context);}
}

HomeFragment:

public class HomeFragment extends BaseFragment implements View.OnClickListener {private Button btn_home;public HomeFragment() {}/*** 加载布局时候调用** @param inflater* @param container* @param savedInstanceState* @return*/@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {// 1. 加载布局,第三个参数必须为`false`,否则会加载两次布局并且抛出异常!!View v = inflater.inflate(R.layout.fragment_home, container, false);btn_home = v.findViewById(R.id.btn_home);btn_home.setOnClickListener(this);return v;}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_home:Log.e(TAG,"点击了home");FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();OneFragment oneFragment = new OneFragment();fragmentTransaction.replace(R.id.fragment,oneFragment);fragmentTransaction.addToBackStack(null);fragmentTransaction.commit();break;}}/*** 加载布局结束后调用** @param savedInstanceState*/@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);}/*** Fragment的布局被移除时调用*/@Overridepublic void onDestroyView() {super.onDestroyView();}/*** Fragment和Activity解除关联的时候调用*/@Overridepublic void onDetach() {super.onDetach();}
}

OneFragment:

public class OneFragment extends BaseFragment implements View.OnClickListener {private Button btn_one;public OneFragment() {}@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View v = inflater.inflate(R.layout.fragment_one, container, false);btn_one = v.findViewById(R.id.btn_one);btn_one.setOnClickListener(this);return v;}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_one:FragmentManager fragmentManager = getFragmentManager();TwoFragment twoFragment = new TwoFragment();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.replace(R.id.fragment,twoFragment);fragmentTransaction.addToBackStack(null);fragmentTransaction.commit();break;}}
}

TwoFragment:

public class TwoFragment extends BaseFragment implements View.OnClickListener {private Button btn_two;public TwoFragment() {}@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View v =  inflater.inflate(R.layout.fragment_two, container, false);btn_two = v.findViewById(R.id.btn_two);btn_two.setOnClickListener(this);return v;}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_two://fragment跳转到Activity与平常不同,注意一下startActivity(new Intent(getActivity(), SecondActivity.class));break;}}
}

SecondActivity:

public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);}
}

六、Fragment的通信

fragment的通信有三种情况,这三种情况都可以用EventBus进行传值。使用传统的方式太麻烦。
EventBus的使用请参考我的另一边博客
EventBus使用超链接
当我们使用EvensBus的时候,有时候收到消息的活动,可能还没有加载,也就是没有进行注册EventBus,这个时候我们使用普通的发送消息是不行的,我们需要使用EventBus的粘性事件。
建议不会使用EventBus或者不会使用EventBus粘性事件的先去上面的链接学习一下。

  1. Fragment向Activity传递数据
  2. Activity向Fragment传递数据
  3. Fragment之间传递数据
    补充一下,本来Event的名字FA代表fragment向Activity传递数据,后来发现AF和FA弄反了,大家凑合看吧。
    将他们写到了一起,先来看看效果。

    首先刚启动的时候我使用EventBus在Activity中发送了粘性事件,默认启动HomeFragment,启动的时候注册EventBus,将1111传递到HomeFragment中(Activity向Fragment传递数据),在HomeFragment中我点击home,发送粘性事件,将2222传递到OneFragment(Fragment之间传递数据)。当我点击two的时候,将3333传递到SecondActivity(Fragment向Activity传递数据)。

下面来看代码:
根据上面的回退栈的代码做了一些修改,只发布修改的地方
目录:

MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private HomeFragment homeFragment;private FragmentManager fragmentManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {showFragment();}private void showFragment() {//发布粘性事件EventBus.getDefault().postSticky(new FAEvetn("1111"));//获取FragmentManager管理对象fragmentManager = getSupportFragmentManager();//获取FragmentTransaction事物对象,并开启事务FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();//创建fragment对象homeFragment = new HomeFragment();//操作fragment,布局ID,fragment对象fragmentTransaction.add(R.id.fragment, homeFragment);//提交事务fragmentTransaction.commit();}@Overridepublic void onClick(View v) {switch (v.getId()) {}}@Overrideprotected void onDestroy() {super.onDestroy();}
}

HomeFragment:

public class HomeFragment extends BaseFragment implements View.OnClickListener {private Button btn_home;private EditText et_home;public HomeFragment() {}/*** 加载布局时候调用** @param inflater* @param container* @param savedInstanceState* @return*/@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {// 1. 加载布局,第三个参数必须为`false`,否则会加载两次布局并且抛出异常!!View v = inflater.inflate(R.layout.fragment_home, container, false);btn_home = v.findViewById(R.id.btn_home);et_home = v.findViewById(R.id.et_home);btn_home.setOnClickListener(this);if(!EventBus.getDefault().isRegistered(this)){EventBus.getDefault().register(this);}return v;}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_home://发布粘性事件EventBus.getDefault().postSticky(new FFEvetn("2222"));FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();OneFragment oneFragment = new OneFragment();fragmentTransaction.replace(R.id.fragment,oneFragment);fragmentTransaction.addToBackStack(null);fragmentTransaction.commit();break;}}/*** 接收来自MainActivity的粘性事件* @param faEvetn*/@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)public void faEvent(FAEvetn faEvetn) {et_home.setText(faEvetn.fa);}@Overridepublic void onDestroy() {EventBus.getDefault().unregister(this);super.onDestroy();}/*** 加载布局结束后调用** @param savedInstanceState*/@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);}/*** Fragment的布局被移除时调用*/@Overridepublic void onDestroyView() {super.onDestroyView();}/*** Fragment和Activity解除关联的时候调用*/@Overridepublic void onDetach() {super.onDetach();}
}

OneFragment:

public class OneFragment extends BaseFragment implements View.OnClickListener {private Button btn_one;private EditText et_one;public OneFragment() {}@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View v = inflater.inflate(R.layout.fragment_one, container, false);btn_one = v.findViewById(R.id.btn_one);et_one = v.findViewById(R.id.et_one);btn_one.setOnClickListener(this);EventBus.getDefault().register(this);return v;}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_one:FragmentManager fragmentManager = getFragmentManager();TwoFragment twoFragment = new TwoFragment();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.replace(R.id.fragment, twoFragment);fragmentTransaction.addToBackStack(null);fragmentTransaction.commit();break;}}/*** 接收来自HomeFragment的粘性事件* @param ffEvetn*/@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)public void faEvent(FFEvetn ffEvetn) {et_one.setText(ffEvetn.ff);}@Overridepublic void onDestroy() {EventBus.getDefault().unregister(this);super.onDestroy();}
}

SecondActivity:

public class SecondActivity extends AppCompatActivity {private TextView tv_second_show;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);initView();EventBus.getDefault().register(this);}private void initView() {tv_second_show = (TextView) findViewById(R.id.tv_second_show);}@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)public void afEvent(AFEvrnt afEvrnt){tv_second_show.setText(afEvrnt.af);}@Overrideprotected void onDestroy() {EventBus.getDefault().unregister(this);super.onDestroy();}
}

activity_second.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".SecondActivity"><TextViewandroid:id="@+id/tv"android:text="第二个Activity"android:gravity="center"android:layout_width="match_parent"android:layout_height="wrap_content"></TextView><TextViewandroid:layout_below="@+id/tv"android:id="@+id/tv_second_show"android:textColor="@color/colorAccent"android:layout_width="match_parent"android:layout_height="wrap_content"></TextView>
</RelativeLayout>

FAEvent:

public class FAEvetn {public String fa;public FAEvetn(String fa) {this.fa = fa;}
}

FFEvent:

public class FFEvetn {public String ff;public FFEvetn(String ff) {this.ff = ff;}
}

AFEvrnt:

public class AFEvrnt {public String af;public AFEvrnt(String af) {this.af = af;}
}

七、Fragment工具类

通过对Fragment的使用,自己写了一个工具类,可以直接拿来用,在使用过程如果有补充或者错误的欢迎提出来,后续有需要了会对工具类进行补充。

/*** Create by dhd on 2021/04/21* Describe : Fragment管理工具类* 建议在调用方法传入fragment对象时进行非null判断,为null则创建对象传入,否则直接传入对象即可,不要一直new对象* 提交事务的四种方式以及是否添加回退栈可根据自己的需要去修改使用*/
public class FragmentHelper {private static String TAG = FragmentHelper.class.getSimpleName();private volatile static FragmentHelper fragmentHelper;private static FragmentManager fragmentManager;private static FragmentTransaction fragmentTransaction;public static FragmentHelper getInstance() {if (fragmentHelper == null) {synchronized (FragmentHelper.class) {if (fragmentHelper == null) {fragmentHelper = new FragmentHelper();}}}return fragmentHelper;}/*** 向Activity中添加一个Fragment* 注意这里的R.id.fragment需要换成你自己Fragment的id* 使用示例: FragmentHelper.getInstance().addFragment(new HomeFragment(), this);** @param fragment fragment对象* @param activity 当前Activity*/public void addFragment(Fragment fragment, AppCompatActivity activity, String tag) {fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.add(R.id.framement, fragment, tag).addToBackStack(tag).commit();}/*** 向Activity中添加一个Fragment* 注意这里的R.id.fragment需要换成你自己Fragment的id* 使用示例: FragmentHelper.getInstance().addFragment(new HomeFragment(), this);** @param fragment fragment对象* @param activity 当前Activity*/public void addFragment(Fragment fragment, AppCompatActivity activity, Bundle bundle, String tag) {fragment.setArguments(bundle);fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.add(R.id.framement, fragment, tag).addToBackStack(tag).commit();}/*** 从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁** @param fragmentId xml布局中Fragment的id,例如FragmentHelper.getInstance().removeFragment(R.id.fragment, (AppCompatActivity) getActivity());* @param activity   当前Activity*/public void removeFragment(int fragmentId, AppCompatActivity activity) {fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(fragmentId);fragmentTransaction.remove(fragment).commit();}/*** 使用另一个Fragment替换当前的,实际上就是remove()然后add()的合体* 注意这里的R.id.fragment需要换成你自己Fragment的id** @param fragment fragment对象* @param activity 当前Activity*/public void replaceFragment(Fragment fragment, AppCompatActivity activity, String tag) {fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.replace(R.id.framement, fragment, tag).addToBackStack(tag).commit();}/*** 带参数的fragment切换* 读取 sourceType = getFragmentManager().findFragmentByTag("fragment").getArguments().getInt("sourceType");** @param fragment* @param activity* @param bundle*/public void replaceFragment(Fragment fragment, AppCompatActivity activity, Bundle bundle, String tag) {fragment.setArguments(bundle);fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.replace(R.id.framement, fragment, tag).addToBackStack(tag).commit();}/*** 隐藏当前的Fragment,仅仅是设为不可见,并不会销毁** @param fragmentId xml布局中Fragment的id* @param activity   当前Activity*/public void hideFragment(int fragmentId, AppCompatActivity activity) {fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(fragmentId);fragmentTransaction.hide(fragment).commit();}/*** 显示之前隐藏的Fragment** @param fragmentId xml布局中Fragment的id* @param activity   当前Activity*/public void showFragment(int fragmentId, AppCompatActivity activity) {fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(fragmentId);fragmentTransaction.show(fragment).commit();}/*** 将view从UI中移除,只是销毁其视图结构,实例并不会被销毁,不会调用onDestory方法,只到onStop** @param fragmentId xml布局中Fragment的id* @param activity   当前Activity*/public void detachFragment(int fragmentId, AppCompatActivity activity) {fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(fragmentId);fragmentTransaction.detach(fragment).commit();}/*** 重建view视图,附加到UI上并显示** @param fragmentId xml布局中Fragment的id* @param activity   当前Activity*/public void attachFragment(int fragmentId, AppCompatActivity activity) {fragmentManager = activity.getSupportFragmentManager();fragmentTransaction = fragmentManager.beginTransaction();Fragment fragment = fragmentManager.findFragmentById(fragmentId);fragmentTransaction.attach(fragment).commit();}//    /**
//     * 回退到上一层fragment,如果已经是最后一层,则退出此Activity
//     *
//     * @param activity 当前Activity
//     */
//    public void backFragment(AppCompatActivity activity) {
//        if (fragmentManager.getBackStackEntryCount() <= 1) {
//            activity.finish();
//        } else {
//            fragmentManager.popBackStack();
//        }
//    }/*** https://blog.csdn.net/qq_16247851/article/details/52793061** @param activity 返回指定的fragment* @param tag*/public void backFragment(AppCompatActivity activity, String tag) {if (fragmentManager.getBackStackEntryCount() <= 1) {activity.finish();} else {//0为弹出flags为0时,弹出该//fragment以上的Fragment,如果是1,弹出该fragment(包括该fragment)以//上的fragment。fragmentManager.popBackStack(tag, 0);}}/*** 如果不是在指定的fragment回退一次,若处于指定的fragment则回退到指定的fragment中** @return*/public static void backFragment(AppCompatActivity activity) {// 获取当前回退栈中的Fragment个数int backStackEntryCount = fragmentManager.getBackStackEntryCount();// 判断当前回退栈中的fragment个数,if (backStackEntryCount > 1) {// 获取当前退到了哪一个Fragment上,重新获取当前的Fragment回退栈中的个数FragmentManager.BackStackEntry backStack = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1);// 获取当前栈顶的Fragment的标记值String tag = backStack.getName();// 判断当前是哪一个标记if (tag.equals("sweepCodeReturnedFragment")) {FragmentHelper.getInstance().backFragment(activity, "homeFragment");} else if (tag.equals("adminFragment")) {FragmentHelper.getInstance().backFragment(activity, "homeFragment");}  else {fragmentManager.popBackStack();}} else {//当回退栈中只有一个fragment的处理方式}}}

总结

  1. Fragment总是作为Activity界面的组成部分,Fragment可以调用getActivity()方法来获取它所在的Activity,Activity可以调用FragmentManager的findFragmentById()或findFragmentByTag()方法来获取Fragment
  2. 一个Activity可以同时拥有多个Fragment,反过来,一个Fragment也可以被多个Activity复用
  3. Fragmrnt拥有自己的生命周期,但是fragment的生命周期直接被所在Activity的生命周期控制
  4. 在Activity运行过程中,可以调用FragmentManager的add()、remove()、replace()方法动态的添加、删除、替换Fragment

fragment的使用暂时就先介绍到这里有啥错误或者不对的地方欢迎提出,最后附上源码下载地址:
链接:https://pan.baidu.com/s/14OcE_ZZzNesi5tIevWw7Rw
提取码:h4tz

Android app包下fragment详细使用相关推荐

  1. 【爱加密】Android App应用安全加固详细步骤

    原文地址:点击打开链接 随着各种牌子手机的不断推出,各种Android手机应用,即Android App也是满天飞.但是,在这个山寨.黑客遍布的世界,如何保证Android App的安全是广大Andr ...

  2. Android App包瘦身优化

    Android App包瘦身优化 APK瘦身是对程序体验的优化,更大的APK需要占用更多的存储空间. APK的构成 APK瘦身前通过Analyze app分析出来的图片(打开方式:Android St ...

  3. android app根目录下cache,Android 手机存储目录详解

    一.手机存储 (一)内置私有存储,手机需root后才能看到 获取路径的方法 1.getFilesDir() /data/data/[packagename]/files 文件缓存目录,一般存小的文件缓 ...

  4. Android App包瘦身优化实践

    随着业务的快速迭代增长,美团App里不断引入新的业务逻辑代码.图片资源和第三方SDK,直接导致APK体积不断增长.包体积增长带来的问题越来越多,如CDN流量费用增加.用户安装成功率降低,甚至可能会影响 ...

  5. android app根目录下cache,Android 缓存目录 Context.getExternalFilesDir()和Context.getExternalCacheDir()方法...

    一.基础知识 应用程序在运行的过程中如果需要向手机上保存数据,一般是把数据保存在SDcard中的. 大部分应用是直接在SDCard的根目录下创建一个文件夹,然后把数据保存在该文件夹中. 这样当该应用被 ...

  6. android wifi在待机状态下可用,Android APP休眠状态下无法联网和播放音频解决方案...

    https://developer.android.google.cn/guide/topics/media/mediaplayer?hl=zh-cn 使用唤醒锁定 当设计在后台播放媒体内容的应用时, ...

  7. android 页面标题,Android v4包下的PagerTitleStrip,ViewPager的页面标题

    android.support.v4.view.PagerTitleStrip 将Page的Title分离出来的一个自定义View,这样可以灵活的设置title的样式.文本. 效果: xml使用: a ...

  8. Android APK包反编译详细步骤教程

    下载安卓apk包反编译软件: https://download.csdn.net/download/LordForce/87485642 1. 解压 dex2jar-2.0.rar 文件. 2. 将 ...

  9. android启动分析,Android APP启动方式、启动流程及启动优化分析

    本文章向大家介绍Android app应用启动的一些相关知识,包括app启动方式.app启动流程和app启动优化等知识! app应用启动方式 1.冷启动 当启动应用时,后台没有该应用的进程,这时系统会 ...

最新文章

  1. HBase的安装与使用
  2. httpclient base64 文件上传_选择HttpClient还是OkHttp?
  3. 全年营业额怎么计算_门店盈亏平衡计算及案例分析 | 商品管理
  4. OutOfMemoryError:无法创建新的本机线程–神秘化的问题
  5. Docker 架构原理及简单使用
  6. 网络管理员&MCSE2003之2:使用虚拟机Vmware建立多电脑网络环境
  7. BlueIdea 7周年 北京欢天喜地大聚会
  8. java复习系列[1] - Java 基础
  9. Linux-Monitor-Tools
  10. 可任意设置时间的ppt倒计时软件
  11. Web前端开发CSS学习笔记2—五大类选择器
  12. Cmd Markdown 简明语法手册
  13. 亚马逊云服务AWS Marketplace “重塑”企业软件SaaS之旅
  14. mysql5.5免安装版教程_mysql 5.5.56免安装版配置方法
  15. 算法导论——钢条切割问题(C语言)
  16. 洛谷—P3387 【模板】缩点
  17. 脉冲宽度调制(PWM)和DAC转换练习
  18. 使用百度翻译api支持中转英,中简转中繁等等
  19. Android实现简单的计算器
  20. java_枚举类型(支付方式枚举)

热门文章

  1. Spring Boot 集成 批处理框架Spring batch
  2. 【每日蓝桥】17、一三年省赛Java组真题“带分数”
  3. 单月涨粉30w+,他们掌握引流法宝,小红书1月创作趋势是什么?
  4. vscode怎样新建项目和文件
  5. 信息化故事--温州的传奇(11)从“进城务工”看“温州新版自闭症”
  6. HUAWEI 机试题:工厂流水线调度
  7. 水表计量单位_关于民用水表,你知道多少?
  8. 宁愿吃生活的苦,也不愿坚持学习
  9. Ubuntu 16.04+网易云音乐+Adobe Flash+腾讯QQ
  10. 七夕节 看到许多停止更新的blog 莫名有点淡淡的忧桑