Fragment(一)--Fragment用法常见问题
2017-06-12 01:35
453 查看
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,用于实现对话框。他的优点是:即使旋转屏幕,也能保留对话框状态。相关文章推荐
- TabHost的基本用法及常见问题
- CString的GetBuffer用法,GetBuffer本质,GetBuffer常见问题解决方法
- document.body的一些用法以及js中的常见问题
- [Android开发常见问题-16] FragmentActivity cannot be resolve to a type
- bochs工具用法以及常见问题小结
- android webView 的常见问题与高级用法
- Fragment 常见问题
- Java常见问题之this()和super()的用法
- const 关键字意义,用法与常见问题
- CString的GetBuffer用法,GetBuffer本质,GetBuffer常见问题解决方法
- python初学常见问题记录(3)--Ipython用法
- git push用法和常见问题分析
- 数据库设计常见问题、基本惯用法及规范(总结)
- git push用法和常见问题分析
- CString的GetBuffer用法,GetBuffer本质,GetBuffer常见问题解决方法
- pthread_cancel用法及常见问题
- CString的GetBuffer用法,GetBuffer本质,GetBuffer常见问题解决方法
- git push用法和常见问题分析
- CString的GetBuffer用法,GetBuffer本质,GetBuffer常见问题解决方法
- git push用法和常见问题分析