Android Fragment 深入理解

来源:互联网 发布:心蓝软件 编辑:程序博客网 时间:2024/05/01 21:30

本文将讲解Fragment 的出现历史
                    Fragment 的生命周期
                    Fragment 动态调用
                    Fragment 的管理
                    Fragment 与Activity的沟通

 1. Fragment的产生与介绍

     Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应平板神马超级大屏的。难道无法做到一个App可以同时适应手机和平板么,当然了,必须有啊。Fragment的出现就是为了解决这样的问题。你可以把Fragment当成Activity的一个界面的一个组成部分,甚至Activity的界面可以完全有不同的Fragment组成,更帅气的是Fragment拥有自己的生命周期和接收、处理用户的事件,这样就不必在Activity写一堆控件的事件处理的代码了。更为重要的是,你可以动态的添加、替换和移除某个Fragment。

2. Fragment的生命周期

  

从上图我们一眼就可以明白Fragment 的生命周期是怎么回事,然并卵。

  1. onAttach(Activity) called once the fragment is associated with its activity.

     在这个fragment 和 activity相连接的时候就会调用,如activity中的 ft.attach(Activity);

2. onCreate(Bundle) called to do initial creation of the fragment.

     初始化 fragment的时候就会调用到

  1. onCreateView(LayoutInflater, ViewGroup, Bundle) creates and returns the view hierarchy associated with the fragment.

      创建和返回fragment 的view 层次

  1. onActivityCreated(Bundle) tells the fragment that its activity has completed its own Activity.onCreate().
  2. 告诉fragment 它的Activity 已经完成了onCreate(),一般是在这里面完成创建的最后一步,但是这里很多时候是进行耗时的操作
  3. onViewStateRestored(Bundle) tells the fragment that all of the saved state of its view hierarchy has been restored.
  4. 通知fragment 它的所有的view的需要保存的状态已经被保存了,这个一般是在需要保存fragment 一些状态的时候才会使用到
  5. onStart() makes the fragment visible to the user (based on its containing activity being started).
  6. onResume() makes the fragment begin interacting with the user (based on its containing activity being resumed).

As a fragment is no longer being used, it goes through a reverse series of callbacks:

  1. onPause() fragment is no longer interacting with the user either because its activity is being paused or a fragment operation is modifying it in the activity.
  2. onStop() fragment is no longer visible to the user either because its activity is being stopped or a fragment operation is modifying it in the activity.
  3. onDestroyView() allows the fragment to clean up resources associated with its View.
  4. onDestroy() called to do final cleanup of the fragment's state.
  5. onDetach() called immediately prior to the fragment no longer being associated with its activity.

 

当我们在程序中动态的加载使用fragment 的时候,才会慢慢的体会深入理解其生命周期的重要性:

    a. onAttach()

@Overridepublic void onAttach(Activity activity) {Log.v(TAG, "onAttach");super.onAttach(activity);mContext = activity;try {mListener = (OnSearchResultItemFragmentListener) activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString()+ " must implement OnFragmentInteractionListener");}}
public interface OnSearchResultItemFragmentListener {// TODO: Update argument type and namepublic void onSRIFragmentInteraction(String id);public ArrayList<User> getSearchedUserList();}


这段代码来自于fragment,可以看到onAttach 是继承而来,它传递的这个 参数非常的有用,因为它将创建Activity 的数据传递给了Fragment,它为frgment 与 activity 的无缝沟通提供了生命的种子. 事实上,它有两方面的作用:

          1. activity 实现 

interface OnSearchResultItemFragmentListener

           这样就保证了当Fragment 里面想要获取到activity 的数据时,能够通过这个mListener 回调来调用Activity 的实现,这样其实是跑Activity的代码,这种设计模式是委托模式

         2. activity 将自己的数据通过activity 传递给了 mContext;

     b.  

     可以看到Fragment比Activity多了几个额外的生命周期回调方法:
      onAttach(Activity)
      当Fragment与Activity发生关联时调用。
      onCreateView(LayoutInflater, ViewGroup,Bundle)
      创建该Fragment的视图
       onActivityCreated(Bundle)
       当Activity的onCreate方法返回时调用
       onDestoryView()
       与onCreateView想对应,当该Fragment的视图被移除时调用
        onDetach()
        与onAttach相对应,当Fragment与Activity关联被取消时调用
       注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现.

       任何试图动态的加载和切换 fragment 的时候,本人一般建议将数据的初始化放在onCreate 中,将试图的初始化放在oncreateVIew中.而需要经常刷新的显示则放在 onStart中

3.动态调用

         一般来讲动态的调用是由Activity 来执行的,所以,任何动态的时机很重要.

        对于具有tab 的activity,就像 我们见到的 微信的主界面的下面的选项,它们的初始化 基本如下代码所示:

请留意下面取值为"@android:id/xx" 的部分,这些名字是不可改的,必须要保持一致

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/fragment_container"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#fafafa"    android:orientation="vertical" >        <TabHost         android:id="@android:id/tabhost"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"        android:paddingLeft="24dp"        android:paddingStart="24dp">        <LinearLayout             android:layout_width="fill_parent"            android:layout_height="fill_parent"            android:orientation="vertical">            <TabWidget                 android:id="@android:id/tabs"                android:layout_width="match_parent"                android:layout_height="48dp"                android:background="#fafafa">                            </TabWidget>                        <View                 android:layout_width="match_parent"                android:layout_height="1dp"                android:background="#cecece"/>                        <FrameLayout                 android:id="@android:id/tabcontent"                android:layout_width="match_parent"                android:layout_height="0dp"                android:layout_weight="1"></FrameLayout>        </LinearLayout>    </TabHost></LinearLayout>

在Activity 中,我们需要在create的时候加入下面的代码,使得创建一个漂亮的tabhost,来提供给大家点击

  private void initializeTabContent() {    Log.d(TAG, "initializeTabContent");    if(mTabHost == null) {    mTabHost = (TabHost)findViewById(android.R.id.tabhost);    }    if(mTabHost == null) {    return;    }    mTabWidget = (TabWidget)mTabHost.findViewById(android.R.id.tabs);    if(mTabWidget != null) {    mTabWidget.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);    }        mTabHost.setup();    mTabHost.clearAllTabs();    mTabHost.setOnTabChangedListener(mTabChangeListener);        TabHost.TabSpec mArticleTabSpec = mTabHost.newTabSpec(ArticleFragment.TAG);    mArticleTabSpec.setIndicator(getTabSelection(mTabHost.getContext(),"TABAritical"));    mArticleTabSpec.setContent(new TabContent(getBaseContext()));    mTabHost.addTab(mArticleTabSpec);        TabHost.TabSpec mHeadlinesTabSpec = mTabHost.newTabSpec(HeadlinesFragment.TAG);    mHeadlinesTabSpec.setIndicator(getTabSelection(mTabHost.getContext(), "TABHeadlines"));    mHeadlinesTabSpec.setContent(new TabContent(getBaseContext()));    mTabHost.addTab(mHeadlinesTabSpec);        }

当我们点击tabhost 的时候,他们的响应函数如下:

 TabHost.OnTabChangeListener mTabChangeListener = new TabHost.OnTabChangeListener() {@Overridepublic void onTabChanged(String tabId) {// TODO Auto-generated method stubLog.d(TAG, "onTabChanged : " + tabId);FragmentManager fm = getFragmentManager();ArticleFragment articleFragment = (ArticleFragment) fm.findFragmentByTag(ArticleFragment.TAG);HeadlinesFragment headlinesFragment = (HeadlinesFragment)fm.findFragmentByTag(HeadlinesFragment.TAG);FragmentTransaction ft = fm.beginTransaction();if(articleFragment != null) {ft.detach(articleFragment);}if(headlinesFragment != null) {ft.detach(headlinesFragment);}if(tabId.equalsIgnoreCase(ArticleFragment.TAG)) {if(articleFragment == null) {ft.add(android.R.id.tabcontent, ArticleFragment.Instance(), ArticleFragment.TAG);} else {ft.attach(articleFragment);}} else if (tabId.equalsIgnoreCase(HeadlinesFragment.TAG)) {if (headlinesFragment == null) {ft.add(android.R.id.tabcontent, HeadlinesFragment.instance(), HeadlinesFragment.TAG);} else {ft.attach(headlinesFragment);}}ft.commitAllowingStateLoss();}};
 请联合add ,attach, detach, replace ,在生命周期中的作用,根据自己的需要来量身定制

5.关于 通信

    在2中我已经介绍了基本的通用方案,为了让通信更加合理,fragment 与activity 的实现符合高内聚低耦合的面向对象规则,我们要采用将 activity 当成中间通道和主体

    fragment A  -> activity-> fragmentB , 或者,fragmentA   <-> activity,

   请记住,这个是设计模式中的委托模式。


对于更加深入的了解,请参考 fragment backstackRecord 理解


0 0
原创粉丝点击