Android Fragment★★
Posted 孟芳芳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Fragment★★相关的知识,希望对你有一定的参考价值。
1.Fragment
fragment译为“碎片”,是android 3.0(API 11)提出的,最开始是为了适配大屏的平板。
Fragment看起来和Activity一样,是一个用户界面。可以结合多个Fragment到一个activity中来构建一个有多方面功能的UI,还可以重用同一个Fragment在多个activity中。Fragment可以当成是activity的一个组件,每个Fragment有单独的生命周期,可以在activity运行时进行添加和移除。因此,相比较于activity,Fragment更加轻量级,更加灵活。
一个Fragment总是被植入到一个activity中 ,并且它的生命周期受该activity直接影响,比如activity处于暂停,则其中的Fragment都暂停;activity销毁,则所有Fragment都销毁。但是,当一个activity运行时,你可以独立的操作每一个Fragment,比如添加和删除它们。进行类似的操作时,可以将Fragment添加到被activity管理的后退栈中,这样用户可以通过点击返回按钮来返回之前打开的Fragment。
Fragment可以作为activity的一部分添加到布局文件中,通过声明元素作为ViewGroup的一部分。也可以将Fragment作为一个没有自己UI的不可见的activity的工人。
总结一下:
①Fragment依赖于Activity,不能独立存在。
②一个Activity里可以有多个Fragment。
③一个Fragment可以被多个Activity重用。
③Fragment有自己的生命周期,并能接收输入事件。
④可以在Activity运行时动态地添加或删除Fragment。
2.Fragment生命周期
常见的周期流程:
①Activity加载Fragment的时候,依次调用:onAttach() -> onCreate() -> onCreateView() -> onActivityCreated() -> onStart() ->onResume()
②当做出一个悬浮的对话框风格的Activity或者其他,就是让Fragment所在的Activity可见,但不获得焦点:onPause()
③当对话框关闭,Activity又获得了焦点: onResume()
④当替换Fragment,并调用addToBackStack()将它添加到后退栈中:onPause() -> onStop() -> onDestoryView() 。注意,此时的Fragment还没有被销毁。
⑤当按下键盘的回退键,Fragment会再次显示出来:onCreateView() -> onActivityCreated() -> onStart() -> onResume()
⑥如果替换后,在事务commit之前没有调用addToBackStack()方法将Fragment添加到后退栈中,或者退出了Activity,那么Fragment将会被完全结束,进入销毁状态: onPause() -> onStop() -> onDestoryView() -> onDestory() -> onDetach()
3.Fragment创建
①静态加载--以<fragment>标签的形式添加到Activity的布局中。
1)定义Fragment的布局,即fragment的布局文件
2)自定义一个Fragment类,需要继承Fragment或它的子类,重写onCreateView()方法,在该方法中调用inflater.inflate()方法加载Fragment的布局文件,接着返回加载的view对象。
public class Fragmentone extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
if(view == null)
View view = inflater.inflate( R.layout.fragment1, container,false);
return view;
3)在需要加载Fragment的Activity对应的布局文件中添加fragment标签,注意name属性是全限定类名,即包含Fragment的包名。
4)Activity在onCreate( )方法中调用setContentView()加载布局文件。
②动态加载--通过java代码将fragment添加到已存在的宿主Activity中
动态添加fragment常用的类:
FragmentManager:用来管理Activity中的fragment,app包中使用getFragmentManager() ,v4包中使用getSupportFragmentManager。可以通过findFragmentById获取指定的Fragment,可以调用popBackStack()方法弹出后台Fragment,还可以调用addToBackStack()方法加入栈,或监听后台栈的变化:addOnBackStackChangeListener。
FragmentTransaction:事务,用来添加、移除、替换fragment,记得在操作完后要用commit()提交事务。
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
transaction.add();往Activity中添加一个Fragment
transaction.remove();从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
transaction.replace():使用另一个Fragment替换当前Fragment,实际上就是remove()然后add()的合体。
transaction.hide();隐藏当前的Fragment,仅仅是设为不可见,并不会销毁。
transaction.show():显示之前隐藏的Fragment。
transaction.commit():提交一个事务。
detach():将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护。
注意:在用fragment的时候,可能会经常遇到Activity状态不一致:State loss这样的错误。主要是因为:commit方法一定要在Activity.onSaveInstance()之前调用。
这些基本是操作Fragment的所有方式了,在一个事务开启到提交可以进行多个添加、移除、替换等操作。
注意:使用Fragment,一定要清楚这些方法,哪个会销毁视图,哪个会销毁实例,哪个仅仅只是隐藏,这样才能更好的使用它们。
attach():重建view视图,附加到UI上并显示。
1)比如:在FragmentA中的EditText填了一些数据,当切换到FragmentB时,如果希望回到A还能看到数据,则使用的就是hide和show。也就是说,希望保留用户操作的面板可以使用hide和show,当然了不要使劲在那new实例,进行下非null判断。
2)再比如:不希望保留用户操作,可以使用remove(),然后add();或者使用replace()这个和remove、add是相同的效果。
3)remove和detach有一点细微的区别:在不考虑回退栈的情况下,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。那么二者怎么取舍使用呢?如果当前Activity一直存在,在不希望保留用户操作的时候,可以优先使用detach。
4.Fragment与Activity的交互
1)组件获取
Fragment获得Activity中的组件: getActivity().findViewById(R.id.list);
Activity获得Fragment中的组件(根据id和tag都可以):getFragmentManager.findFragmentByid(R.id.fragment1);
2)数据传递
①Activity传递数据给Fragment
采用Bundle方式:在activity中创建Bundle数据包,把要传的值存入bundle,调用Fragment实例的setArguments(bundle)从而将Bundle数据包传给Fragment,然后Fragment中调用getArguments获得Bundle对象,进行解析就可以了。
举个例子:动态添加fragment的时候,在添加每个fragment之前,使用Bundle传输数据给每个fragment。
mManager = getSupportFragmentManager();
mTransaction = mManager.beginTransaction();
homeFragment = new HomeFragment();
//创建Bundle对象,并存储数据
Bundle bundle=new Bundle();
bundle.putString("home","Home");
homeFragment.setArguments(bundle);
fragment中接收数据:
Bundle bundle = this.getArguments();
String home = bundle.getString("home");
②Fragment传递数据给Activity
采用接口回调方式:在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口,Fragment就可以通过回调接口传数据了。
首先在Fragment 中定义一个回调接口:
public interface ICallBack
public void getResult(String result);
并在Fragment中设置接口回调的方法:
public void getData(ICallBack callBack)
String msg = editText.getText().toString();
callBack.getResult(msg);
最后在Activity中回调:
leftFragment.getData(new ICallBack()
@Override
public void getResult(String result)
Toast.makeText(this, result, 1).show();
);
③Fragment与Fragment之间的数据互传
不同fragment之间的通信要依靠activity来完成。可以看成Fragment->Activity->Fragment,因为两个或多个fragment依附于同一个activity,所以完全可以通过把值传递到共同依附的Activity,然后通过Bundle传给另一个fragment。
方式一:先调用findFragmentById()方法根据id获得fragment对象,然后调用fragment中的方法进行赋值。
manager.findFragmentById(); //根据ID找到对应的Fragment实例,主要用在静态添加fragment的布局中,因为静态添加的fragment才会有ID
manager.findFragmentByTag();//根据TAG找到对应的Fragment实例,主要用于在动态添加的fragment中,根据TAG找到fragment实例
manager.getFragments();//获取所有被ADD进Activity中的Fragment
然后,直接在一个Fragment中调用另外一个Fragment的公开方法,前提是要先拿到另外一个Fragment的实例。
一般情况下,都是动态添加Fragment的,所以通过在add每个Fragment的时候,给每个Fragment设置个tag。
manager = this.getSupportFragmentManager();
transaction = manager.beginTransaction();
LeftFragment leftFragment = new LeftFragment();
RightFragment rightFragment = new RightFragment();
transaction.add(R.id.left, leftFragment, "left");
transaction.add(R.id.right, rightFragment, "right");
transaction.commit();
在Activity创建的时候,添加上所有的fragment,并为每个fragment设置tag,这样才会在每个fragment中通过findFragmentByTag()时不会出现空指针。
在LeftFragment中:
RightFragment rightFragment = (RightFragment) getActivity().getSupportFragmentManager().findFragmentByTag("right");
if (rightFragment == null) return;
rightFragment .setTextView("right now");
这样就实现了在LeftFragment里给RightFragment传值的效果。
这种方式是两个fragment直接通信的。(不推荐使用)
方式二:通过接口回调的方法实现两个fragment之间的通信
比如点击MessageFragment的Button按钮,给CommunityFragment中的TextView传递数据,就需要在MessageFragment中定义接口,并定义回调的方法,该方法的参数中传一个String字符串。接着让附属Activity实现这个接口并重写回调方法,也就得到了传过来的数据,然后通过findFragmentByTag()的方法获取要传给的CommunityFragment的实例。
在CommunityFragment中定义一个方法用来接收这个数据,然后用对象直接调用这个方法将参数传递给这个方法就可以了。
方式三:其他方式
EventBus:使用方便,但其使用的是反射原理,会有稍微的延迟,并且他人维护不方便;
static静态变量:使用方便,但是每个static变量都会占用一块内存区,Android系统分配给每个App的内存是有限的(63M),过多很容易造成App内存溢出;
广播Broadcast Receiver:Android的广播是有限制的,除了系统的广播外,其他的广播尽量少用。另外,广播会有延迟;
接口:接口是常用的Fragment之间的通讯方式,通过一个主Activity作为通讯桥梁(谷歌官方声明:两个Fragment之间永远不要直接通讯),实现两个Fragment之间的通讯。
接口的方式是推荐的,但是,传统的接口方式会造成一些问题,如果主Activity实现了多个Fragment的通讯回调接口,那就需要implements很多接口,类中还要实现一大堆接口的方法,显得有点繁琐。
以上是关于Android Fragment★★的主要内容,如果未能解决你的问题,请参考以下文章