fragment的基本概念
fragment是Activity的一部分,它必须依赖于Activity,它也有自己的生命周期,一个Activity里可以有一个或多个fragment,并且可以删除或者添加fragment,Fragment可以被多个Activity重用。
注意:support-v4库中也开发一套Fragment API,过去support-v4库是一个jar包,24.2.0版本开始,将support-v4库模块化为多个jar包,包含:support-fragment,support-ui,support-media-compat等,这么做是为了减少APK包的大小,需要哪个模块就引入哪个模块。例如:项引入support-v4库,则compile 'com.android.support:support-v4:24.2.1',如果只想引入support-fragment库,则‘com.android.support:support-fragment:24.2.1’
support库是不断更新的,因此使用support库中support.v4.app.Fragment比较好,不要使用系统自带的android.app.Fragment.如果要使用support库的Fragment,Activity必须继承FragmentActivity(AppCompatActivity是FragmentActivity的子类)
fragment的生命周期:
onAttach(Activity)
当Fragment与Activity发生关联时调用,可以通过该方法获取activity引用,还可以通过getArguments()获取参数
onCreate()
Fragment被创建时调用
onCreateView(LayoutInflater,ViewGroup,Bundle)
创建该Fragment的视图
onActivityCreated(Bundle)
当Activity的onCreate方法返回时调用
onStart()
当Fragment可见时调用
onResume()
当Fragment可见且可交互时调用
onPause()
当Fragment不可交互但可见时调用
onStop()
当Fragment不可见时调用
onDestoryView()
与onCreateView相对应,当该Fragment的视图被转移时调用
onDetach()
当Fragment和Activity解除关联时调用
与onAttach相对应,当Fragment与Activity关联被取消时调用
上面的方法只有onCreateView()在重写时不用写super方法,其他都需要
fragment的好处:
1.模块化:不必要把所有代码全部写在Activity中,而是把代码写在各自的Fragment中
2.可重用:多个Activity可重用一个Fragment
3.克适配:根据屏幕尺寸,屏幕方向,能够方便地实现不同的布局。
fragment的核心类:
Fragment:Fragment的基类,任何创建的Fragment都需要继承该类
FragmentManager:管理和维护Fragment,是抽象类,具体的实现类是FragmentManagerIMpI.
FragmentTransaction:对Fragment的添加,删除等操作都需要通过事务方式进行,是抽象类,具体的实现类是BackStackRecord
Nested Fragment(Fragment内部嵌套Fragment的能力),通过getChildFragmentManager()能够获得管理自Fragment的FragmentManager,在子Fragment中可以通过getParentFragment()获得父Fragment.
使用fragment的方式:
1.静态使用:
用一个例子简单说明:一个布局有标题和内容,标题和内容都是是fragment。
上面是内容fragment
上面是标题fragment
下面是MainActivity的布局文件:
核心思想就是·将fragment当作是view来看待加进Activity中,所有控件的事务都交给各自的fragment去做。静态添加的缺点是一旦添加了就不能删除
2.动态使用
只讲述使用support.v4.app.Fragment,首先activity必须继承FragmnetActivity.
1.在Activity定义所要添加的fragment的实例
private FragmentManager manager;//为了管理Activity中的fragments,需要使用FragmentManager
那么使用FragmentManager可以做的工作有哪些呢:
1.得到Activity中存在的fragment:使用findFragmentById()或findFragmentByTag()方法。
2.将fragment弹出back stack:popBackStack:将back stack中最后一次的fragment转换弹出。如果没有可以出栈的东西,返回false.
这个函数是异步的:它将弹出栈的请求加入队列,但是这个动作直到应用回到事件循环才会执行。
3.为back stack加上监听器
****注意****
当使用Fragment时,可以通过用户交互来执行一些动作,比如增加、移除、替换等,所有这些的改变构成一个集合,这个集合叫做一个transaction.
可以调用FragmentTransaction中的方法来处理这个transaction,并且可以将transaction存进由activity管理的back stack中,这样用户就可以进行fragment变化的回退操作。
那么如何得到这个实例呢?
manager = getSupportFragmentManager();
public TabDynamicFragment tabDynamicFragment;
public TabMeFragment tabMeFragment;
public TabMessageFragment tabMessageFragment;
public TabMeFragment tabMeFragment;
public TabMessageFragment tabMessageFragment;
private void showFragment(int page) {
FragmentTransaction ft = manager.beginTransaction();
// 想要显示一个fragment,先隐藏所有fragment,防止重叠
hideFragments(ft);
switch (page) {
case 0://主页
// 如果fragment1已经存在则将其显示出来
if (drFragment != null)
ft.show(drFragment);
// 否则添加fragment1,注意添加后是会显示出来的,replace方法也是先remove后add
else {
drFragment = new DRFragment();
ft.add(R.id.tabhome_fragment, drFragment);
}
flag = 1;
changecolor(flag);
break;
case 1://动态
if (tabDynamicFragment != null)
ft.show(tabDynamicFragment);
else {
tabDynamicFragment = new TabDynamicFragment();
ft.add(R.id.tabhome_fragment, tabDynamicFragment);
if (isFirstEnterDynamic) {
isFirstEnterDynamic = false;
SharedPreferences.Editor edit = sp.edit();
edit.putString("onceDynamic", "onceDynamic");
edit.commit();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
tabDynamicFragment.showGuideDialog();
}
}, 300);
}
}
flag = 2;
changecolor(flag);
break;
case 2://消息
if (tabMessageFragment != null) {
ft.show(tabMessageFragment);
} else {
tabMessageFragment = new TabMessageFragment();
ft.add(R.id.tabhome_fragment, tabMessageFragment);
}
flag = 3;
changecolor(flag);
break;
case 3://我的页面
if (tabMeFragment != null) {
ft.show(tabMeFragment);
// tabMeFragment.doCheckEvent();
} else {
tabMeFragment = new TabMeFragment();
ft.add(R.id.tabhome_fragment, tabMeFragment);
}
flag = 4;
changecolor(flag);
break;
}
ft.commit();//事务提交,很关键
}
// 当fragment已被实例化,相当于发生过切换,就隐藏起来
public void hideFragments(FragmentTransaction ft) {
if (drFragment != null)
ft.hide(drFragment);
if (tabDynamicFragment != null)
ft.hide(tabDynamicFragment);
if (tabMessageFragment != null)
ft.hide(tabMessageFragment);
if (tabMeFragment != null)
ft.hide(tabMeFragment);
}
FragmentTransaction ft = manager.beginTransaction();
// 想要显示一个fragment,先隐藏所有fragment,防止重叠
hideFragments(ft);
switch (page) {
case 0://主页
// 如果fragment1已经存在则将其显示出来
if (drFragment != null)
ft.show(drFragment);
// 否则添加fragment1,注意添加后是会显示出来的,replace方法也是先remove后add
else {
drFragment = new DRFragment();
ft.add(R.id.tabhome_fragment, drFragment);
}
flag = 1;
changecolor(flag);
break;
case 1://动态
if (tabDynamicFragment != null)
ft.show(tabDynamicFragment);
else {
tabDynamicFragment = new TabDynamicFragment();
ft.add(R.id.tabhome_fragment, tabDynamicFragment);
if (isFirstEnterDynamic) {
isFirstEnterDynamic = false;
SharedPreferences.Editor edit = sp.edit();
edit.putString("onceDynamic", "onceDynamic");
edit.commit();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
tabDynamicFragment.showGuideDialog();
}
}, 300);
}
}
flag = 2;
changecolor(flag);
break;
case 2://消息
if (tabMessageFragment != null) {
ft.show(tabMessageFragment);
} else {
tabMessageFragment = new TabMessageFragment();
ft.add(R.id.tabhome_fragment, tabMessageFragment);
}
flag = 3;
changecolor(flag);
break;
case 3://我的页面
if (tabMeFragment != null) {
ft.show(tabMeFragment);
// tabMeFragment.doCheckEvent();
} else {
tabMeFragment = new TabMeFragment();
ft.add(R.id.tabhome_fragment, tabMeFragment);
}
flag = 4;
changecolor(flag);
break;
}
ft.commit();//事务提交,很关键
}
// 当fragment已被实例化,相当于发生过切换,就隐藏起来
public void hideFragments(FragmentTransaction ft) {
if (drFragment != null)
ft.hide(drFragment);
if (tabDynamicFragment != null)
ft.hide(tabDynamicFragment);
if (tabMessageFragment != null)
ft.hide(tabMessageFragment);
if (tabMeFragment != null)
ft.hide(tabMeFragment);
}
实现Fragment懒加载
实现的目标是,当Fragment对我们可见时,才进行网络加载,然后再解析数据,更新UI.
在Fragment中有一个setUserVisibleHint这个方法,而且这个方法是优于onCreate()方法的,所以可以作为Fragment的一个生命周期来看待,它会通过·1isVisibleToUser
告诉当前Fragment是否可见
可以重写setUserVisibleHint方法,然后可见进行网络加载数据
public void setUserVisibleHint(boolean isVisibleToUser){
if(isVisibleToUser){
pullData();
super.setUserVisibleHint(isVisbleToUser);
}
}
根据实际用途使用懒加载
因为setUserVisibleHint(boolea isVisibleToUser)方法是比onCreate更早调用的,但是一般在加数据时,都会在数据加载完成时进行UI更新,所以有一个问题,假如
拉取数据是秒回,但是没有进行UI绑定,或者Adapter初始化,就无法更新UI,但是可以通过另一个方法getUserVisibleHint(),这个方法判断当前Fragment是否可见,可以在
一系列变量初始化在判断是否可见,若可见进行数据拉取
if(getUserVisibleHint){
pullData();
}