• Fragment(一)--Fragment用法常见问题


    fragment notes##

    fragment相关内容包括

    基本定义与使用
    回退栈内部实现
    fragment通信(与activity 与fragment)
    DialogFragment
    VP + Fragment
    嵌套Fragment
    懒加载

    基本定义与使用(5个)

    fragment依赖于Activity,不能独立存在

    一个Activity可以有多个Fragment

    一个Fragment可以被多个Activity复用

    Fragment有自己的生命周期,并能接受输入事件

    能在Activity运行时动态添加或删除Fragment

    Fragment优势:(3个)

    1.模块化Modularity

    从此不用在一个Activity写所有的代码。而是把代码写在各自的Fragment中。

    2.可重用Resuability
    多个Activity可复用同一个Fragment

    3.可适配Adaptability
    根据硬件的屏幕尺寸和方向选择不同的布局

    Fragment核心类:(3个)

    Fragment:任何Fragment的基类

    FragmentManager:管理Fragment。FM是抽象类,实现类是FragmentManagerImpl

    FragmentTransaction:对Fragment操作,包括添加,删除登需要通过事务处理。FT是抽象类,实现类是BackStackRecord.

    Nested Fragment(Fragment内部嵌套Fragment的能力)是Android 4.2提出的.support-fragment库可以兼容到1.6。通过getChildFragmentManager()能够获得管理子Fragment的FragmentManager,在子Fragment中可以通过getParentFragment()获得父Fragment。

    	public class Fragment1 extends Fragment{
    
    private static String ARG_PARAM = "param_key";
    
    private String mParam;
    private Activity mActivity;
    
    public void onAttach(Context context) {
        mActivity = (Activity) context;
        mParam = getArguments().getString(ARG_PARAM);  //获取参数
    }
    
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_1, container, false);
        TextView view = root.findViewById(R.id.text);
        view.setText(mParam);
        return root;
    }
    
    public static Fragment1 newInstance(String str) {
        Fragment1 frag = new Fragment1();
        Bundle bundle = new Bundle();
        bundle.putString(ARG_PARAM, str);
        fragment.setArguments(bundle);   //设置参数
        return fragment;
    }
    }
    

    Fragment有很多可以复写的方法,其中最常用的就是onCreateView(),该方法返回Fragment的UI布局,需要注意的是inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常

    Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
    

    创建Fragment时传参必须使用setArguments(Bundle b)###

    如果在创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,

    原因:

    因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据。

    这点很重要。否则可能导致严重后果!!!

    取参数在onAttached()中取,context上下文也要在该处取###

    我们可以在Fragment的onAttach()中通过getArguments()获得传进来的参数,并在之后使用这些参数。如果要获取Activity对象,不建议调用getActivity(),而是在onAttach()中将Context对象强转为Activity对象。

    在Activity中添加Fragment的方式有两种:

    静态添加:在xml中通过的方式添加,缺点是一旦添加就不能在运行时删除。
    动态添加:运行时添加,这种方式比较灵活,因此建议使用这种方式。

    虽然Fragment能在XML中添加,但是这只是一个语法糖而已,Fragment并不是一个View,而是和Activity同一层次的

    1.Activity提供容器
    首先Activity需要有一个容器存放Fragment,一般是FrameLayout,因此在Activity的布局文件中加入FrameLayout:

    然后在onCreate()中,通过以下代码将Fragment添加进Activity中。

    if (bundle == null) {
    getSupportFragmentManager().beginTransaction()
        .add(R.id.container, Fragment1.newInstance("hello world"), "f1")
        //.addToBackStack("fname")
        .commit();
    }
    

    需要注意的有如下几点:

    因为我们使用了support库的Fragment,因此需要使用getSupportFragmentManager()获取FragmentManager。

    add()是对Fragment众多操作中的一种,还有remove(), replace()等,第一个参数是根容器的id(FrameLayout的id,即”@id/container”),第二个参数是Fragment对象,第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")从FragmentManager中查找Fragment对象。

    在一次事务中,可以做多个操作,比如同时做add().remove().replace()。

    commit()操作是异步的。内部通过mManager.enqueueAction()加入处理队列。

    对应的同步方法为commitNow(),commit()内部会有checkStateLoss()操作,如果开发人员使用不当(比如commit()操作在onSaveInstanceState()之后),可能会抛出异常解决方案和产生分析

    commitAllowingStateLoss()方法则是不会抛出异常版本的commit()方法,但是尽量使用commit(),而不要使用commitAllowingStateLoss()。

    addToBackStack("fname")是可选的。FragmentManager拥有回退栈(BackStack),类似于Activity的任务栈,如果添加了该语句,就把该事务加入回退栈,当用户点击返回按钮,会回退该事务(回退指的是如果事务是add(frag1),那么回退操作就是remove(frag1));如果没添加该语句,用户点击返回按钮会直接销毁Activity。

    Fragment有一个常见的问题,即Fragment重叠问题,这是由于Fragment被系统杀掉,并重新初始化时再次将fragment加入activity,因此通过在外围加if语句能判断此时是否是被系统杀掉并重新初始化的情况。

    Fragment有个常见的异常:

    java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
    

    从上面看到,先从mAdded中查找是否有该Fragment,如果没找到,再从mActive中查找是否有该Fragment。mAdded是已经添加到Activity的Fragment的集合,mActive不仅包含mAdded,还包含虽然不在Activity中,但还在回退栈中的Fragment。

    该异常出现的原因是:commit()在onSaveInstanceState()后调用。首先,onSaveInstanceState()在onPause()之后,onStop()之前调用。onRestoreInstanceState()在onStart()之后,onResume()之前。

    因此避免出现该异常的方案有:

    不要把Fragment事务放在异步线程的回调中,比如不要把Fragment事务放在AsyncTask的onPostExecute(),因此onPostExecute()可能会在onSaveInstanceState()之后执行。
    逼不得已时(即一定会出现事务丢失时)使用commitAllowingStateLoss()。

    FragmentTransaction有一些基本方法,下面给出调用这些方法时,Fragment生命周期的变化:

    add(): onAttach()->…->onResume()。

    remove(): onPause()->…->onDetach()。

    replace(): 相当于旧Fragment调用remove(),新Fragment调用add()。

    show(): 不调用任何生命周期方法,调用该方法的前提是要显示的Fragment已经被添加到容器,只是纯粹把Fragment UI的setVisibility为true。

    hide(): 不调用任何生命周期方法,调用该方法的前提是要显示的Fragment已经被添加到容器,只是纯粹把Fragment UI的setVisibility为false。

    detach(): onPause()->onStop()->onDestroyView()。UI从布局中移除,但是仍然被FragmentManager管理。

    attach(): onCreateView()->onStart()->onResume()。

    Fragment实现原理与BackStack

    Fragment向Activity传递数据

    首先,在Fragment中定义接口,并让Activity实现该接口

    在Fragment的onAttach()中,将参数Context强转为OnFragmentInteractionListener对象:

    **FABridge
    **

    由于通过接口的方式从Fragment向Activity进行数据传递比较麻烦,需要在Fragment中定义interface,并让Activity实现该interface,FABridge通过注解的形式免去了这些定义。

    Activity向Fragment传递数据

    Activity向Fragment传递数据比较简单,获取Fragment对象,并调用Fragment的方法即可,比如要将一个字符串传递给Fragment,则在Fragment中定义方法

    Fragment之间通信

    由于Fragment之间是没有任何依赖关系的,因此如果要进行Fragment之间的通信,建议通过Activity作为中介,不要Fragment之间直接通信。

    DialogFragment

    DialogFragment是Android 3.0提出的,代替了Dialog,用于实现对话框。他的优点是:即使旋转屏幕,也能保留对话框状态。

  • 相关阅读:
    jstack使用-倒出线程堆栈
    sentos nginx安装
    阿里云主机添加云磁盘
    redis 安装并设置为开机启动服务
    curl命令使用小结[转]
    FormView控件下DropDownList是否可以绑定
    数据绑定之DataFormatString
    GridView控件RowDataBound事件中获取列字段值的几种途径 !!!
    怎么用SQL语句备份和恢复数据库?
    XtraReports 入门教程
  • 原文地址:https://www.cnblogs.com/zharma/p/8345963.html
Copyright © 2020-2023  润新知