内容简介:因为前一篇关于底部导航Fragment 表示 Activity 中的行为或用户界面部分。您可以将多个片段组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个片段。您可以
因为前一篇关于底部导航 BottomNavigationView
的使用,所以需要用 Fragment
来代替之前的 activity
。作为的一个android新手,因为一直在用activity,几乎没有用到 fragment
的时候,所以这次要从头开始学习使用。 写到fragment的时候想到了 Lifecycle
和 LiveData
,用来管理生命周期,但是想了一想决定先不用。因为同时上手多个不会的内容有点导致混乱。
理解Fragment,fragment如何被调用?
- 怎么理解片段:
Fragment 表示 Activity 中的行为或用户界面部分。您可以将多个片段组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个片段。您可以 将片段视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件 ,并且您可以在 Activity 运行时添加或移除片段(有点像您可以在不同 Activity 中重复使用的“子 Activity”)。
- 为什么需要片段:
利用片段实现此类设计时,您无需管理对视图层次结构的复杂更改。通过将 Activity 布局分成片段,您可以在运行时修改 Activity 的外观,并在由 Activity 管理的返回栈中保留这些更改。 您应该将每个片段都设计为可重复使用的模块化 Activity 组件。也就是说,由于每个片段都会通过各自的生命周期回调来定义其自己的布局和行为,您可以将一个片段加入多个 Activity,因此,您应该采用可复用式设计,避免直接从某个片段直接操纵另一个片段。
- 如何使用fragment?
当您将片段作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且片段会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明片段,将其作为 <fragment>
元素插入您的 Activity 布局中,或者通过将其添加到某个现有 ViewGroup,利用应用代码进行插入。不过,片段并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的片段用作 Activity 的不可见工作线程。
也就是如下代码,但是昨天别人的XML中,使用的是FrameLayout,为什么呢?
<fragment class="xxx.xxx.xxx" android:id="@+id/fragment_placeholder" android:layout_gravity="top" android:layout_width="match_parent" android:layout_height="wrap_content"> </fragment> 复制代码
在StackOverflow上,找到解答: 使用FrameLayout动态更改fragment
改变的方式为:
getSupportFragmentManager().beginTransaction().replace(R.id.IDxxx,fragment).commit(); 复制代码
开始简单使用fragment
fragment的生命周期
各个阶段发生了什么?文章参考
onAttached() onCreateView() onActivityCreated() onDestroyView() onDetach() onCreate(),onCreateView(),onActivityCreated()
一旦activity进入resumed状态(也就是running状态),你就可以自由地添加和删除fragment了。因此,只有当activity在resumed状态时,fragment的生命周期才能独立的运转,其它时候是依赖于activity的生命周期变化的。
重写方法以创建简单的Fragment
知道了activity在调用fragment的时候调用了 OnCreateView
,知道了在最简单的情景下,我们可以不用重写其他任何方法。也就是不传递任何参数,也不考虑任何其他的东西,只是想展示一个 fragment
界面。 而重写 onCreateView
需要的就是返回 Fragment
的布局文件。使用动态注入的方式完成。关于inflate方法,这里不展开,总之就是一个能在 Fragment
和 Activity
中动态注入View的方法。 Fragment
的代码
public class testFragment extends Fragment { public testFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_test, container, false); } } 复制代码
使用 Fragment
:
Fragment test = new testFragment(); //... getSupportFragmentManager().beginTransaction().replace(R.id.fragment_placeholder,test).commit(); 复制代码
这就是一个最简单的fragment使用. 接下来,为了在项目中使用,我们必然要向 Fragment
传递数据吧,设置列表,设置用户信息等等。 而相应的,比如用户修改了自己的头像,修改了自己的名字,我们也会需要保存数据。不过现在还说到数据库,就先不管了。
向Fragment中传递需要的数据
一般而言,我们通过构造函数来提供Class创建中需要的数据,但是Fragment的构造函数必须是无参数。在官方API中,我们看到原因:对于用户自定义的构造参数,android想要在fragment重新加载的时候,不知道怎么调用。所以必须要调用默认的构造函数
Every fragment must have an empty constructor, so it can be instantiated when restoring its activity's state. It is strongly recommended that subclasses do not have other constructors with parameters, since these constructors will not be called when the fragment is re-instantiated; instead, arguments can be supplied by the caller with setArguments(Bundle) and later retrieved by the Fragment with getArguments().
那问题来了,我Activity重新加载的时候怎么没这些事儿呢?咋就你那么多事呢? 好的,对于你这种暴躁小老弟,我问一句,你创建Activity会使用构造函数的呢? 问题来了,activity和fragment分别是怎么销毁和重新创建的?为了理解这个问题,先来理解观察一下它们的生命周期
fragment和activity的生命周期
官方文档-fragment生命周期 是我们最好的朋友 官方文档-activity生命周期
综上,我觉得你对的你自己说的: 销毁和重建
其实根本没有正确的认识,来问你几个问题
- 一个Activity或者Fragment的界面上出现了一个对话框,导致他们变成了半透明。这是你说的销毁和重建吗?这种情况下经历了它们的哪些生命周期?
- 从一个Activity或者Fragment的界面离开,也就是从可见到不可见再到可见,这是,我不用问你用jio想也知道,这个是销毁和重建。这种情况下经历了哪些生命周期?参考文章
在这些Paused Stopped Resumed Start的状态中,数据状态的怎么变化的呢?参考
一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会得到保留. 但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有该activity的实例对象了. 如果之后这个activity重新回到前台, 之前所作的改变就会消失. 为了避免此种情况的发生, 开发者可以覆写onSaveInstanceState()方法. onSaveInstanceState()方法接受一个Bundle类型的参数, 开发者可以将状态数据存储到这个Bundle对象中, 这样即使activity被系统摧毁, 当用户重新启动这个activity而调用它的onCreate()方法时, 上述的Bundle对象会作为实参传递给onCreate()方法, 开发者可以从Bundle对象中取出保存的数据, 然后利用这些数据将activity恢复到被摧毁之前的状态.
Activity和Fragment的数据传递的不同
感觉到学了生命周期之后,觉得其实这没有解答我的疑惑:为什么 Activity和Fragment传递数据的方式不一样
?其实重新整理一下我的疑惑:
- 为什么Fragment不能使用自定义的构造函数?理由是:
Every fragment must have an empty constructor, so it can be instantiated when restoring its activity’s state 在恢复它的状态时,通过调用默认构造函数来使其实例化。
-
那个恢复它的状态是什么时候的事情呢? onPause()或者onStop()方法调用后,如果系统内存不足,就会摧毁它。然后重新使用的时候会从onCreate开始重新实例化。 相应的,如果系统资源充足,就不会摧毁它,也不必重新实例化。
-
那这个newInstance()方法做了什么?为什么相应的Activity不需要设置newInstance()方法?
activity中的传递数据如下,
class Fisrt extends Activity{ @Override onCreate(Bundle savedInstanceState){ //省略 intent.putExtra(xxx); StartActivity(intent); } } //----------------------------------------------------- class Second extends Activity{ @Override onCreate(Bundle savedInstanceState){ //省略 intent = getIntent() value = intent.getExtra(xxx) } } 复制代码
而Fragment不一样,它被调用需要实现 newInstance
方法
public class testFragment extends Fragment { TextView textView; private static final String ARG_PARAM1 = "param1"; private String mParam1; public testFragment() { // Required empty public constructor } public static testFragment newInstance(String s ) { testFragment fragment = new testFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, s); fragment.setArguments(args); return fragment; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_test, container, false); textView = view.findViewById(R.id.test_TextView); textView.setText(mParam1); return view; } } 复制代码
Activity的startActivity()方法
?在上一点的对比后,不禁让人疑惑,突然感到,我们一直熟悉的Activity启动,突然之间变得不熟悉了。 Fragment
的 newInstance()
其实阅读以下就很能理解,是在这个方法中调用了构造方法,并且用Bundle传递了参数。
但是我们的Activity呢?谁调用了它的构造方法? 更进一步,Bundle是做什么用的?是谁在调用Activity和Fragment的生命周期? 各个生命周期执行了什么代码,完成了各个生命周期的功能?
因为着急完成项目,这个地方的知识曲线太过陡峭。我需要先放置一下参考文章1,参考文章2 结论就是:StartActivity中 新的Activity类是通过类加载器方式即通过反射的方式生成的 。我们可以看一下mInstrumentation.newActivity()方法:
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity)cl.loadClass(className).newInstance(); } 复制代码
而对于我的疑惑而言,也明了了,Activity的创建也有一个newInstance。所以其实我传递一个参数给Fragment需要做的步骤,Activity中也都做了,只是你不知道而言。
结论
给 Fragment
传递数据,是不能通过构造方法的。我们需要 new Fragment
实例后,给这个实例里放一个包装袋,里面装的有我们想要的数据,这个包装袋就是:
Bundle args = new Bundle(); args.putString(ARG_PARAM1, s); 复制代码
对包装袋的存取方法是:
fragment.setArguments(args); //存 //------- mParam1 = getArguments().getString(ARG_PARAM1); //取 复制代码
因为这个方法是实例化Fragment,所以必须
- 有一个static方法,里面有有
new Fragment
,然后 把传递进来的数据放到包装袋 中,并把包装袋放到fragment - 我们要拿这些数据有两种情况,第一次新建和Fragment因为内存不足被销毁。其他时候,即使是不可见状态,会重新调用
onCreateView()
,但是只要不被销毁,就不用调用这些数据。所以从包装袋那数据必然是在onCreate()
生命周期中
public static testFragment newInstance(String s ) { testFragment fragment = new testFragment(); Bundle args = new Bundle();//包装袋 args.putString(ARG_PARAM1, s); fragment.setArguments(args);//放置包装袋 return fragment; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); } } 复制代码
总结
首先 我们的Activity呢?谁调用了它的构造方法? 更进一步,Bundle是做什么用的?是谁在调用Activity和Fragment的生命周期? 各个生命周期执行了什么代码,完成了各个生命周期的功能? 上面的问题是需要弄懂的,但是又觉得对项目没有什么用,感觉很难投入精力啊。
第二呢,对于Fragment有了一些认知,下一步就是把之前项目里的Activity写成Fragment了。
以上所述就是小编给大家介绍的《项目实践-Fragment学习(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。