Fragment分四个部分出题:
1、为什么Fragment被称为第五大组件
2、Fragment生命周期
3、Fragment的通信
4、Fragment管理器FragmentManager
为什么Fragment被称为第五大组件
1)为什么会出现Fragment:解决屏幕碎片化的问题
2)Fragment加载到Activity中的方法
①静态加载
②动态加载:
//第一步:获得FragmentTransaction
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//第二步:使用FragmentTransaction的add方法将Fragment对象加入Fragment栈中
ft.add(R.id.fragment_container,new RightFragment(),"rightFragment");
ft.addToBackStack("rightFragment");
//提交事务
ft.commit();
Fragment的生命周期
Fragment生命周期方法含义:
public void onAttach(Context context)
onAttach()方法会在Fragment与Activity窗口关联后立刻调用。从该方法开始,就可以通过Fragment.getActivity()方法获取与Fragment关联的Activtiy窗口对象,但因为Fragment的控件未初始化,所以不能够操作控件。
public void onCreate(Bundle savedInstanceState)
在调用完onAttach()执行完之后,立即就会调用onCreate()方法,可以在Bundle对象中获取一些在Activity中传过来的数据。通常会在该方法中读取保存的转态,获取或初始化一些数据。在该方法中不要进行耗时操作,不然Activity窗口不会显示。
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
该方法是Fragment很重要的一个生命周期方法,因为会在该方法中创建Fragment显示的View,其中inflater是用来装载布局文件的,container是<fragment>标签的父标签对应对象,saveInstanceState参数可以获取Fragment保存的转态,如果未保存那么就为null。
public void onViewCreated(View view,Bundle savedInstanceState)
Android在创建完Fragment中的View对象之后,会立刻回调该方法。其中view参数就是onCreateView中返回的view,而bundle对象用于一般用途。
public void onActivityCreated(Bundle savedInstanceState)
在Activity的onCreate()方法执行完之后,Android系统会立刻调用该方法,表示Activity窗口已经初始化完成,从这一个时候开始,就可以在Fragment中使用getActivity().findViewById(R.id.xxx);来操作Activity中的view了。
public void onStart()
这个没啥可讲的,但是一个细节需要知道,当系统调用该方法的时候,fragment已经显示在UI上了,但还不能进行互动,因为onResume()方法还没有执行完。
public void onResume()
该方法为fragment从创建到显示Android系统调用的最后一个生命周期方法,调用完该方法时候,fragment就可以与用户互动了。
public void onPause()
fragment由活动状态变成非活跃执行的第一个回调方法,通常可以在这个方法中保存一些需要临时暂停的工作。例如:存音乐播放速度,然后在onResume()方法中恢复音乐播放进度。
public void onStop()
当onStop()返回的时候,fragment将从屏幕上消失。
public void onDestoryView()
该方法的调用意味着在onCreateView()中创建的视图都将被移除。
public void onDestroy()
Android在Fragment不再使用时会调用该方法,要注意的是~这是Fragment还和Activity是藕断丝连!并且可以获得Fragment对象,但无法对获得的Fragment进行任何操作。
public void onDetach()
为Fragment生命周期中的最后一个方法,当该方法执行完后,Fragment与Activity不再有关联。
Fragment比Activity多了几个额外的生命周期回调方法:
onAttach(Activity):当Fragment和Activity发生关联时使用。
onCreateView(LayoutInflater,ViewGroup,Bundle):创建该Fragment的视图
onActivityCreate(Bundle):当Activity的onCreate()方法返回时调用
onDestoryView():与onCreateView相对应,当该Fragment的视图被移除时调用
onDetach():与onAttach()相对应,当Fragment与Activity关联被取消时调用
注意:除了onCreateView()方法,其他的所有的方法如果你重写了,必须调用父类对于该方法的实现
回退栈的常见方法:
**(1).```FragmentTransaction.addToBackStack(String)```**
将一个刚刚添加的Fragment加入到回退栈中
**(2).```getSupportFragmentManager().getBackStackEntryCount()```**
获取回退栈中的实体数量
**(3).```getSupportFragmentManager().popBackStack(String name, int flags)```**
根据name立刻弹出栈顶的fragment
**(4).```getSupportFragmentManager().popBackStack(int id, int flags)```**
根据id立刻弹出栈顶的fragment
FragmentPagerAdapter与FragmentStatePagerAdapter的区别
FragmentPagerAdapter适用于页面较少的情况,destroyItem方法中只是调用了fragmentransaction的detach方法
FragmentStatePagerAdapter适用于页面较多的情况,每次切换ViewPager的时候是回收内存的。destroyItem调用了fragmentransaction的remove方法
Fragment的通信
1、Fragment跟Activity的通信:getActivity();
2、Activity中调用Fragment:接口回调
public class MainFragment extends Fragment{
public FragmentListener mListener;
//MainFragment开放的接口
public static interface FragmentListener{
//跳到h5页面
void toH5Page();
//展示消息
void showMsg(String str);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//对传递进来的Activity进行接口转换
if(activity instance FragmentListener){
mListener = ((FragmentListener)activity);
}
}
...其他处理代码省略
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
msgListener.showMsg("Hello 传递数据给Activity展示");
}
});
}
// MainActivity 实现 MainFragment开放的接口
public class MainActivity extends FragmentActivity implements FragmentListener{
@override
public void toH5Page(){... }
@Override
public void showMsg(String str) {
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
}
...其他处理代码省略
}
3、Fragment中调用Fragment :findFragmentById
ContentFragment cf = (ContentFragment) getActivity().getFragmentManager().findFragmentById(R.id.content_fg);
cf.showPro(name);
Fragment管理器FragmentManager
add与replace 的区别:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0324/2639.html
想必题主对于addToBackStack( )这个方法理解不深
这里先解释下这个方法的作用
我们开启一个新的fragment 用下面这种方式
FragmentManager manager = getSupportFragmentManager();
AFragment fragment = new AFragment();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(viewId, fragment);
transaction.addToBackStack();
transaction.commit();
其中对fragment的操作是下面这个方法
transaction.replace(viewId, fragment);
这个方法可以分解成:
transaction.add(viewId, fragment);
transaction.show(fragment);
transaction.hide(preFragment);
transaction.remove(preFragment);
这两种方式是等效的,只是下面的看起来更直白
那么addToBackStack()这个方法究竟做了什么?
调用addToBackStack()后按back键
AFragment 消失,preFragment又出现了,你在fragment的生命周期中加入log就会发现,AFragment销毁,preFragment被重新创建
其实addToBackStack()记录的是一个transaction的操作记录,当你按back键时,相当于调用了
transaction.add(viewId, preFragment);
transaction.show(preFragment);
transaction.hide(fragment);
transaction.remove(fragment);
即transaction操作了100个fragment的行为,一旦按back键,会读取这100个记录,按反方向调用一次 add 变成remove hide 变成show
现在你明白为什么MapFragment不见了吧
Callback.onReplace(R.id.fragment_container,new SettingFragment());
这个封装方法记录的只是SettingFragment代替了MainBizFragment,因此按back键只是反方向调用一次,并没有保存MainBizFragment中已经开启MapFragment这一状态
addToBackStack()保存的是一系列针对一个fragmentTransaction的操作记录
addToBackStack()保存的是一系列针对一个fragmentTransaction的操作记录
addToBackStack()保存的是一系列针对一个fragmentTransaction的操作记录
你只需保存已经开启MapFragment的这一状态就可以了,在MainBizFragment的onResume(或其他更适合的生命周期函数)中判断一下保存的条件,选择性的开启MapFragment即可
使用tab切换Fragment的时候造成重叠问题
我们都知道fragment切换有两种方式:
- replace方式
transaction.replace(R.id.content, IndexFragment);
- add-hide-show方式
transaction.add(R.id.content, IndexFragment);
transaction.hide(otherfragment);
transaction.show(thisfragment);
而上面按钮中出现bug的就是采用第二种方式。然后我们来分析下用add,hide,show为什么出现这种bug,我把每个操作都打印出了以下日志:
复现bug的操作是:
1.首先打开,默认选中的是第一个tab,如上面的一张图片正常那样。
2.切换到tab2,并把tab1 hide掉;
3.再切回到tab1,并不会触发tab1对应fragment的任何生命周期;
4.然后home键进入后台,我在activity的onPause()中手动对IndexFragment赋空,模拟长时间后台,系统销毁了该引用
IndexFragment=null;
5.再次启动,其实tab1 的fragment实例在内存中还在,只是他的引用被销毁了。
6.再切到tab2,这里其实是先把tab1的hide,在show tab2,但是tab1 的fragment引用为空,所以无法hide,就出现了tab2叠在tab1上的花屏情况。
7.再切到tab1,tab1就会重复创建对象。
使用replace方式,虽然这种方式会避免上述的bug,但也是重复创建了对象。因为replace方式,对应的FrameLayout只有一 层,而add方式,这个FrameLayout其实有2层。但是这种方式的缺点是:每次replace会把生命周期全部执行一遍,如果在这些生命周期函数 里拉取数据的话,就会不断重复的加载刷新数据
那么最合适的处理方式是这样的:
1.在add的时候,加上一个tab参数
transaction.add(R.id.content, IndexFragment,”Tab1″);
2.然后当IndexFragment引用被回收置空的话,先通过
IndexFragment=FragmentManager.findFragmentByTag(“Tab1″);
找到对应的引用,然后继续上面的hide,show;