项目实践-Fragment学习(一)

6 篇文章 0 订阅
3 篇文章 0 订阅

前言

因为前一篇关于底部导航BottomNavigationView的使用,所以需要用Fragment来代替之前的activity。作为的一个android新手,因为一直在用activity,几乎没有用到fragment的时候,所以这次要从头开始学习使用。
写到fragment的时候想到了LifecycleLiveData,用来管理生命周期,但是想了一想决定先不用。因为同时上手多个不会的内容有点导致混乱。

理解Fragment,fragment如何被调用?

官方文档-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() —— 当fragment被加入到activity时调用(在这个方法中可以获得所在的activity)。
  • onCreateView() —— 当activity要得到fragment的layout时,调用此方法,fragment在其中创建自己的layout(界面)。
  • onActivityCreated() —— 当activity的onCreated()方法返回后调用此方法
  • onDestroyView() —— 当fragment中的视图被移除的时候,调用这个方法。
  • onDetach() —— 当fragment和activity分离的时候,调用这个方法。
  • 就像activitie一样,在以下的状态中,可以使用Bundle对象保存一个fragment的对象:onCreate(),onCreateView(),onActivityCreated()

一旦activity进入resumed状态(也就是running状态),你就可以自由地添加和删除fragment了。因此,只有当activity在resumed状态时,fragment的生命周期才能独立的运转,其它时候是依赖于activity的生命周期变化的。
在这里插入图片描述

重写方法以创建简单的Fragment

知道了activity在调用fragment的时候调用了OnCreateView,知道了在最简单的情景下,我们可以不用重写其他任何方法。也就是不传递任何参数,也不考虑任何其他的东西,只是想展示一个fragment界面。
而重写onCreateView需要的就是返回Fragment的布局文件。使用动态注入的方式完成。
关于inflate方法,这里不展开,总之就是一个能在FragmentActivity中动态注入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生命周期
在这里插入图片描述
在这里插入图片描述

综上,我觉得你对的你自己说的:销毁和重建其实根本没有正确的认识,来问你几个问题

  1. 一个Activity或者Fragment的界面上出现了一个对话框,导致他们变成了半透明。这是你说的销毁和重建吗?这种情况下经历了它们的哪些生命周期?
  2. 从一个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传递数据的方式不一样?其实重新整理一下我的疑惑:

  1. 为什么Fragment不能使用自定义的构造函数?理由是:

Every fragment must have an empty constructor, so it can be instantiated when restoring its activity’s state
在恢复它的状态时,通过调用默认构造函数来使其实例化。

  1. 那个恢复它的状态是什么时候的事情呢?
    onPause()或者onStop()方法调用后,如果系统内存不足,就会摧毁它。然后重新使用的时候会从onCreate开始重新实例化。
    相应的,如果系统资源充足,就不会摧毁它,也不必重新实例化。

  2. 那这个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启动,突然之间变得不熟悉了。
FragmentnewInstance()其实阅读以下就很能理解,是在这个方法中调用了构造方法,并且用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,所以必须

  1. 有一个static方法,里面有有new Fragment,然后把传递进来的数据放到包装袋中,并把包装袋放到fragment
  2. 我们要拿这些数据有两种情况,第一次新建和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了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值