Android详解fragment

来源:互联网 发布:淘宝全球购买手 编辑:程序博客网 时间:2024/05/05 23:26
fragment有独立的行为,是activity的一部分可以将多个fragment作为activity的一个个模块其实从意义上说就像是子activity一样。fragment必须被activity嵌入,它的生命周期也是和activity紧密相关的。你也可以把fragment添加到一个返回栈里面去,这个返回栈是由activity维护的,这个返回栈记录的是这个activity的发生过的所有fragment变化(java代码函数:transaction ),可以按返回键回退这个fragment变化(transaction)你可以在xml文件中定义fragment或者在代码里手动添加到一个已经存在的viewgroup中。但是!注意一点,fragment可以没有UI界面(其实这个东西因为经验有限,暂时不知道能干吗用)fragment设计的时候主要是用来支持大屏幕(比如平板),动态而且复杂的UI界面,你就可以在activity运行的时候动态的改变里面的内容,而且还能随时回退(因为前面提到过的返回栈)。举个例子:很常见的一个平板的阅读应用,左边是文章的列表,右边是文章内容,点击列表一项,右边的文章内容就改变。这时候就可以用两个fragment,只需要一个页面就可以做这些事了。你设计的时候要把fragment设计成一个模块,一个activity可以复用的组成部分,不能设计成能用一个fragment能直接操纵另一个fragment的这种样子。你可以在不同屏幕大小的手机平板上用不同的fragment组合。比如前面说的阅读应用,在平板上用的两列布局(两个fragment),在手机上就只能用一列布局了。一、创建一个fragment必须继承fragment生命周期(图)Fragment is added|    onAttach()|onCreate()|onCreateView()<----------------------------------------------|onActivityCreated()|onStart()|onResume()|Fragment is activie||User navigatesThe fragment is backward or added to the backfragment isstack,then removed/replacedremoved/replaced||   onpause()||   onstop()||onDestroyView()||---The fragment returns to the layout from the back stack--onDestory()|onDetach()|     Fragment is destoryedfragment和activity看起来很类似,如果你之前写好了页面,你可以直接复制到fragment里面使用。一般来说,你需要至少重写下面几个方法:* onCreate():当创建fragment的时候回调这个方法,这里面初始化重要的组件,这些组件可以在onpause或者stopped之后onresume的时候(其实就是onresume)保留。(好好理解下)*onCreateView():这个方法是当fragment第一次绘制UI的时候调用,这个方法要返回一个view(fragment的view),如果返回null的话,说明这个fragment没有UI界面(前面提过了这样的一种情况)*onPause():这个方法是当用户离开这个fragment的时候调用,当然,并不表示这个fragment就销毁了,用户可能会返回这个界面。但是,用户也有可能不返回这个界面,这就需要你在这个方法里面提交你改变的数据(原文是:你需要在当前用户会话中提交任何你需要保存的变化)有一些封装好了的fragment你可以直接用:DialogFragment:顾名思义,是一个浮动对话框,它可以替代原来我们用的activity的对话框(看样子似乎是推荐这种方式),你可以把这个DialogFragment加到返回栈,然后就可以返回到已经消失的fragment了(不知道干吗用)ListFragment:展示一个数据的list,可以使用 SimpleCursorAdapter这样的适配器,其实就像listactivity。我感觉这个用的不多。PreferenceFragment:设置的界面,相当于PreferenceActivity,其实这个界面用的也不多,不过如果应用的设置界面不需要特别定制的话,这个界面可以很方便的配置一些设置项的。二、添加UI一个fragment的UI也是activity UI的一部分在onCreateView()提供UI界面,前面写过了。注意一下,如果是继承的listfragment的话,onCreateView()默认返回的就是一个listview,所以不需要实现onCreateView()这个方法。这边写个例子:public static class ExampleFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.example_fragment, container, false);}}这边的container就是父布局,比如我们要把fragment插入到activity的B布局里面去,父布局指的就是这个B。savedInstanceState这个就是当fragment执行onresume的时候,从之前的fragment保存了的数据中取出来的。三、给activity添加一个fragment前文已经提过,添加一个fragment的方法有两种:在xml文件里声明或者在代码里添加到一个存在的viewgroup中。xml声明:<xml version="1.0" encoding="utf-8"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><fragment android:name="com.example.news.ArticleListFragment"android:id="@+id/list"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent" /><fragment android:name="com.example.news.ArticleReaderFragment"android:id="@+id/viewer"android:layout_weight="2"android:layout_width="0dp"android:layout_height="match_parent" /></LinearLayout>当系统create这个activity的时候,就会实例化这两个fragment,然后调用fragment的oncreateview方法,系统就会在声明fragment的地方插入oncreateview返回的view(oncreateview如何返回view上文提过)。注意:每一个fragment需要有一个唯一的标识。该标识可以在activity重新启动的时候重新构建fragment(就像是我们要用fragment的各种transactions的时候需要提供这个标识,写代码的时候就会知道这一点了),有三种方式提供这个唯一标识:1.android:id  2.android:tag  3:如果上面两个都没提供,系统会把fragment嵌入的那个viewgroup的id作为自己的唯一标识。四、代码里声明fragment:你可以在任何时候把fragment添加到一个viewgroup里面。可以用 FragmentTransaction类提供的方法进行动态添加,删除等:ExampleFragment fragment = new ExampleFragment();fragmentTransaction.add(R.id.fragment_container, fragment);fragmentTransaction.commit();具体代码的意思不过多解释了。五、添加一个没有UI的fragment用这个方法添加没有UI的fragment: add(Fragment, String),string类型的参数是这个fragment的tag。注意:唯一标识没有UI的fragment只有这种方式。之后可以用findFragmentByTag()找到这个fragment。因为这个fragment没有UI,也没有嵌入任何activity的布局,所以不需要实现oncreateview这个方法。六、管理fragment管理fragment用FragmentManager类,这个类有几个比较重要的作用有UI且在xml声明的fragment用 findFragmentById()或者 findFragmentByTag(),没有UI的用findFragmentByTag()popBackStack(),弹出堆栈里面的fragment。addOnBackStackChangedListener()不解释了。可以用来得到FragmentTransaction,这个上面说过了。七、FragmentTransaction的用法这节比较重要,因为我们用fragment的很大部分原因是因为我们可以动态的添加一个布局,删除布局等等(这个布局有自己的一套声明周期),当把Transaction压入后退栈之后还可以支持回退操作~获得 FragmentTransaction:FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();操作有add(), remove(), replace(),执行操作之后需要commit一下。在commit之前可以 addToBackStack(),这样就可以把这个transaction 放到堆栈里面例子:// Create new fragment and transactionFragment newFragment = new ExampleFragment();FragmentTransaction transaction = getFragmentManager().beginTransaction();// Replace whatever is in the fragment_container view with this fragment,// and add the transaction to the back stacktransaction.replace(R.id.fragment_container, newFragment);transaction.addToBackStack(null);// Commit the transactiontransaction.commit();如果你一下子执行了很多transaction,然后addToBackStack了,那么所有的transaction都会一起放到堆栈里面去,返回的时候也一起返回。有几点注意的:1、commit必须最后执行。2、如果把多个fragment添加到同一个容器里面去的话,那么添加的顺序就决定了这些fragment显示的顺序。如果没有addToBackStack,那么remove这个fragment的时候,这个fragment就destory,销毁了(不可回退)。如果加了addToBackStack,那么remove之后这个fragment会先stop停止,回退的时候会resume,重新构建。(这边的操作不知道是不是对应的ondestory,onstop,onresume的声明周期,回头我验证一下)注意:Transaction可以有动画, 在commit之前先setTransition()就可以了。commit操作不是立即执行的,它运行在UI线程里,知道这个UI线程执行到它(不太理解啊,如果是UI线程的话不就相当于立即执行么?),如果想要立即执行的话,需要执行executePendingTransactions()这个方法,再commit的时候就立即执行了,一般这是不必要的,除非你的 transaction 是依赖其他线程工作的(经验不够,不理解)有一点需要特别注意的,必须让transaction的commit在activity保存状态(也就是离开这个activity)之前!否则会抛出异常。因为commit之后,activity状态会发生改变,如果commit在离开activity之后,那么这个状态可能会丢失,而我们知道activity要回来的时候需要原来保存的状态来重新构建的,所以这就有问题咯。当然,如果你觉得状态丢失无所谓,不要系统抛异常,你可以把commit换成 commitAllowingStateLoss()。八、fragment与activity的通信fragment可以通过getactivity很方便地获得activity的各种layout等:View listView = getActivity().findViewById(R.id.list);activity可以通过FragmentManager的 findFragmentById()或者findFragmentByTag()获得fragment的引用:ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);九、创建一个activity的事件回调方法你可能需要fragment和activity共享一些事件(上文介绍过点击文章列表看文章的例子),这里提供一个比较好方式,那就是在fragment里定义一个接口,然后让activity实现它,当activity接收到回调的时候,就可以把回调带来的信息传递给其他的fragment了。(其实这种方式平时也经常用,就是一般的接口用法)就比如上文提过的文章的例子,可以这么写:public static class FragmentA extends ListFragment {...// Container Activity must implement this interfacepublic interface OnArticleSelectedListener {public void onArticleSelected(Uri articleUri);}...}然后让activity实现这个接口,要确保activity实现了的话,可以用这种方式:public static class FragmentA extends ListFragment {OnArticleSelectedListener mListener;...@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);try {mListener = (OnArticleSelectedListener) activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");}}...}onAttach方法是当fragment添加到activity的时候回调的。activity没有实现这个接口,就抛异常,如果实现了,mListener就有了activity的OnArticleSelectedListener实现引用。这样就可以共享事件了。再说详细一点,举个例子:当fragment发生了一个事件,要通知activity,那么只需要在这个事件发生的时候执行mListener.onArticleSelected(int position)之类的方法。然后因为mlistener是activity接口的引用,activity就会调用他实现的那个方法:onArticleSelected(int position)(这里讲的涉及接口的概念,新手就好好理解下吧)十、处理fragment的生命周期fragment的生命周期和activity很类似。created:onAttach()|onCreate()|onCreateView()|onActivityCreated()|Started:onStart()|Resumed:onResume()|Paused:onpause()|Stopped:onstop()|Destoryed:onDestroyView()|onDestory()|onDetach() fragment在下列三个生命周期中存在:1、Resumed 这个节点上,fragment是可见的,它的activity是运行着的2、Paused 这个节点上,这个fragment的activity依然是可见的,不过前端已经有其他activity了,只不过没有完全遮住它而已。3、Stopped 这个节点上,fragment是不可见的,它的activity可能已经stopped了或者fragment已经被remove出去而且并没有添加到回退栈中。一个已经stopped的fragment依然是alive的,它的状态还是被系统保存的,不过它不会再显示了,直到activity被杀死它也就杀死了。fragment可以像activity一样在重新构建的时候从bunble中获取保存的状态,这个保存过程在onSaveInstanceState()回调方法中执行。在onCreate(), onCreateView(), 或者 onActivityCreated()的时候重新构建。生命周期问题上,activity和fragment最大的区别就是它们存储在各自堆栈的方式不同,activity是存储在系统自动维护的堆栈里(换句话说,就是activity一定会存储),但是fragment是要我们手动去设置存不存储的( addToBackStack()),而且这个堆栈由activity维护。虽然说activity和fragment的生命周期差不多,不过我们要理解一点,就是activity是怎么影响fragment的周期的,下面会讲。特别注意:fragment里面getactivity可以获取上下文,不过要注意一点,当这个fragment还没有attach到这个activity获取已经dettach了,getactivity方法会返回null。十一、fragment和activity生命周期的协调activity生命周期影响fragment,每一个activity的生命周期回调方法会导致fragment回调它的一个名字类似的回调方法。比如说,当activity回调了onpause方法,那么fragment也会回调onpause。大家也看到了,fragment有一些比activity多出来的生命周期:1、onattach,当fragment和activity绑定的时候回调,这个方法会传递一个activity引用。2、onCreateView,这个方法用来创建一个fragment的view3、onActivityCreated,顾名思义,这个方法是在activity的oncreate方法返回之后回调的。4、onDestroyView,当fragment的view被remove的时候回调5、onDetach,当从activity detach的时候回调。当activity到了onresume的时候,我们就可以自由地添加或者删除fragment了,也就是说,只有当activity在onresume生命周期的时候fragment才能独立。当activity不在onresume周期的时候,fragment又要被activity的生命周期带着走了。
原文:http://www.hizhaohui.cn/android%E8%AF%A6%E8%A7%A3fragment/

0 0
原创粉丝点击