1. 前言
这几天接到一个坑的任务,领导要我做一个Android 蓝牙APK,要求是在平板上使用并且横屏分页显示,一边显示蓝牙广播搜索的设备,另一边存放指定已过滤的设备。
在Android中横屏显示,并且分页,自然而然就想到了Fragment,于是抽空学习一下Fragment的用法,并且在使用过程中遇到findFragmentById 返回为null。
今天遇到这个问题,真是头疼死了,找了很多资料都说是这样子使用,在原本可以运行的项目中的findFragmentByid返回值为null,原本可以运行的项目,竟然运行报错。
因此才有这一篇文章。
2. 基本概念
Fragment,又称碎片,也可以说是Activity的一个片段,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6。
Fragment的优势有以下几点:
3. Fragment生命周期(参考菜鸟教程《Fragment基本概述》)
4. Fragment 使用(参考菜鸟教程《Fragment基本概述》)
Fragment 使用有两种方式,分为静态加载Fragment 和 动态加载Fragment
4.1 静态加载Fragment
对于静态加载需要注意的是:
4.1.1. 通过xml的方式添加,缺点是一旦添加就不能在运行时删除
4.1.2 自定义一个Fragment类,需要继承Fragment或者他的子类,重写onCreateView()方法 在该方法中调用:Inflater.inflate()方法加载Fragment的布局XML文件,接着返回加载的view对象,在Inflater.inflat方法中的第三个参数必须为false,因为它还要停靠在容器中。
第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常:
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call
4.1.3 在需要加载Fragment的Activity或者父Fragment(Fragment 包含Fragment) 对应的布局文件中添加fragment的标签, 记住,name属性是全限定类名哦,就是要包含Fragment的包名,如下:
public abstract class BaseFragment extends Fragment
{
protected View mRootView;
protected Activity mActivity;
@Override
public void onCreate(Bundle saveInstanceState)
{
super.onCreate(saveInstanceState);
mActivity = getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return initView();
};
//当fragment 依赖的activity onCreate方法结束时使用
@Override
public void onActivityCreated(Bundle saveInstanceState)
{
super.onActivityCreated(saveInstanceState);
initData();
}
//子类必须初始化
public abstract View initView();
//子类初始化数据
public abstract void initData();
}
4.2 动态加载Fragment(参考菜鸟教程《Fragment基本概述》)
4.2.1 在动态添加方式中,首先需要Activity 或者 父Fragment 中有一个
一个容器存放Fragment,一般是FrameLayout,因此在Activity的布局文件中加入FrameLayout:
在onCreate()
中,通过以下代码将Fragment添加进Activity中
if (bundle == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, Fragment1.newInstance("hello world"), "f1")
.commit();
}
使用动态方式,add()方法的第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")
从FragmentManager中查找Fragment对象。
5. Fragment与Activity的交互(参考菜鸟教程《Fragment基本概述》)
5.1Fragment向Activity传递数据
在Fragment中定义接口,并让Activity实现该接口。
5.2 Activity向Fragment传递数据
Activity向Fragment传递数据比较简单,获取Fragment对象,并调用Fragment的方法即可,比如要将一个字符串传递给Fragmen
5.3Fragment之间通信
由于Fragment之间是没有任何依赖关系的,因此如果要进行Fragment之间的通信,建议通过Activity作为中介,不要Fragment之间直接通信,如下:
6. 在Fragment 中获取控件的方法,
mRootView = UIUtils.inflate(R.layout.fragment_home_left_layout);
mRefreshLayout = (SwipeRefreshLayout) mRootView.findViewById(R.id.refreshLayout);
mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
{
@Override
public void onRefresh() {
scanLeDevice(true);
}
});
listView = (MyListView) mRootView.findViewById(R.id.listView1);
7. Activity中获取Fragment组件的方法
首先getFragmentManager 、getSupportFragmentManager这个两个FragmentManager用的最多,Fragment是安卓3.0以后引入的API,FragmentManager是管理Fragment的片段管理器,直接使用,再
Fragment获得Activity中的组件: getActivity().findViewById(R.id.list);
Activity获得Fragment中的组件(根据id和tag都可以):getFragmentManager.findFragmentByid(R.id.fragment1);
8. Fragment 嵌套使用时,获取组件方法
当Fragment嵌套Fragment时(也就是说你的Fragment里面还有子Fragment),里面需要用getChildFragmentManager来获得FragmentManager,再使用findViewById(R.id.list), 或者findFragmentByid(R.id.fragment1);
关于Fragment 一些基本的认识就这些了,学习还要继续,付出总有回报的。
参考:
《Android Fragment 非常详细的一篇》
Fragment嵌套Fragment中getChildFragmentManager的问题
对于Fragment的一些理解