Fragment

1,简介

Fragment名为碎片和Activity相似。

Fragment用来描述一些行为或一部分用户界面在一个Activity中,你可以合并多个fragment在一个单独的activity中建立多个UI面板,同时重用fragment在多个activity.可以认为fragment作为一个activity中的一节模块 fragment有自己的生命周期,接收自己的输入事件,你可以添加或移除从运行中的activity.

Fragment作为Android 3.0的新特性,有些功能还是比较强大的,比如 合并两个Activity



 可以看到两个Activity通过两个Fragment合并到一个Activity的布局方式,对于平板等大屏幕设备来说有着不错的展示面板。

       如下例子,在一个activity的布局文件中嵌入两个fragment

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"  >

    <TextView 

             android:layout_width="fill_parent"

             android:layout_height="wrap_content"

             android:text="@string/hello" />

   

    <fragment android:name="com.aaa.MainActivity$MyFragment"

            android:id="@+id/fg1"

            android:layout_width="match_parent"

            android:layout_height="wrap_content" />

   

    <fragment android:name="com.aaa.MainActivity$MyFragment2"

            android:id="@+id/fg2"

            android:layout_width="match_parent"

            android:layout_height="wrap_content" />

   

</LinearLayout>

       这样就把两个fragment嵌入到了使用该布局文件的activity中。 使用很简单,和普通的Veiw没有区别。这样也就有一个好处是,布局文件可以重复使用(类似include)。需要说明的是嵌入的Fragment存在于ActivityViewGroup中。

Settings使用PreferenceActivity

Settings模块主界面就是继承自PreferenceActivity,采用headersfragment来显示。

public class Settings extends PreferenceActivity … {

….

@Override

    public void onBuildHeaders(List<Header> target) {

        loadHeadersFromResource(R.xml.settings_headers, target);

        ….

}

    ….

}

 

显示界面使用PreferenceFragment

显示界面都是直接或简介继承自Fragment。比如:网络设置WirelessSettings继承自PreferenceFragmentPreferenceFragmentFragment子类,我们可以根据不同需求来选择使用哪个Fragment,就像选择ActivityListActivity一样。

Fragment:你可以在onCreate方法中使用res/layout/xxx.xml文件,就像activity一样。

PreferenceFragment:如果你显示的为列表,那么你就可以使用PreferenceFragment来实现,它里封装了ListView用作列表显示。其使用的布局文件为res/xml/xxx.xml

 由上可知道Settings界面布局和架构。

例子:

使用fragmentview进行布局。

效果图:

采用相对布局,左边是一个Fragment,右边是两个上下显示的fragment

 JAVA代码如下:定义了三个 fragment,分别使用各自的布局文件。

public static class MyFragment extends Fragment {

         @Override

         public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) {

                   return inflater.inflate(R.layout.myfragment, container, false);

}

    }

public static class MyFragment2 extends Fragment {

                   @Override

                   public View onCreateView(LayoutInflater inflater, ViewGroup container,

                           Bundle savedInstanceState) {

                            return inflater.inflate(R.layout.myfragment2, container, false);

                   }

         }

        

         public static class MyFragment3 extends PreferenceFragment {

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            // Load the preferences from an XML resource

            addPreferencesFromResource(R.xml.my_fragmented2);

        }

}

 

2,生命周期

一个fragment必须总是嵌入在一个activity中,同时fragment的生命周期受activity而影响。

其生命周期如下图所示:


 

可看见Framment生命周期比较复杂,如果你熟悉activity的生命周期,那么Fragment的生命周期也是类似的。Activityfragment回调顺序如下:

activity.onCreate

  fragment.onAttach

  fragment.onCreate

activity.onStart

  fragment.onActivityCreated

  fragment.onStart

activity.onResume

  fragment.onResume

  fragment.onStop

activity.onStop

  fragment.onDestroyView

  fragment.onDestroy

  fragment.onDetach

activity.onDestroy

       可知道当activity 暂停,那么所有在这个activityfragments将被destroy释放。 你可以在activity的不同生命周期中,对fragment执行不同操作。

 3Fragment简单示例

自定义一个fragment,需要继承(或间接继承)Fragment类。

public class MyFragment extends Fragment {

        

         @Override

         public View onCreateView(LayoutInflater inflater, ViewGroup container,

                 Bundle savedInstanceState) {

                  

                   return inflater.inflate(R.layout.myfragment, container, false);

         }

 

}

onCreateView()

当系统调用fragment在首次绘制用户界面时,如果画一个UI在你的fragment你必须返回一个View当然了你可以返回null代表这个fragment没有UI.

 myfragment.xml.  和普通的layout定义完全一样。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

         <Button 

            android:id="@+id/btn"

             android:layout_width="fill_parent"

             android:layout_height="wrap_content"

             android:text="@string/hello"

             />

</LinearLayout>

 FragmentManager

可以使用FragmentManager来管理Fragment。在Activity中通getFragmentManagerFragmentManager 一些主要的方法有通findFragmentById()取一个Activity中有Fragment布局。当然findFragmentByTag()方法,以及Fragment中出popBackStack()可以注册 addOnBackStackChangedListener()管理具体的可以在android.app.FragmentManager中了解

      可以使用FragmentManager进行事物处理。

//通过begintransaction方法获取一个事物处理实例。

FragmentTransaction transaction = fragmentManager.beginTransaction();

在这期间可以使用 add(), remove()replace()。最终需要改变时执行 commit()即可。

如下例子:替换activity的布局为,MyFragment

public void onCreate(Bundle savedInstanceState) {

         super.onCreate(savedInstanceState);

         Log.i(TAG, "onCreate");

        

         FragmentManager fragmentManager = this.getFragmentManager();

         FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

         fragmentTransaction.replace(android.R.id.content, new MyFragment());

         fragmentTransaction.commit();

}

 

我们可以使用FragmentManager来获取嵌入到activityfragment

<fragment android:name="com.aaa.MainActivity$MyFragment"

            android:id="@+id/myFg"

            android:tag="myFragment"

            android:layout_width="match_parent"

            android:layout_height="wrap_content" />

getFragmentManager().findFragmentById(R.id.myFg);

getFragmentManager().findFragmentByTag(“myFragment”);

Headers及其使用

Headers在平板上和Fragment合使用的比多。如Settings

使用就承自PreferenceActivity,然后重写onBuildHeaders方法,调用loadHeadersFromResource方法加载headers.xml

 my_headers.xml

<?xml version="1.0" encoding="utf-8"?>

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">

 

    <header android:fragment="com.aaa.MyHeadersPreferenceActivity$MyFragmentTest1"

            android:icon="@drawable/ic_1"

            android:title="Prefs Test 1"

            android:summary="An example of some preferences." />

           

    <header android:fragment="com.aaa.MyHeadersPreferenceActivity$MyFragmentTest2"

            android:icon="@drawable/ic_2"

            android:title="Prefs Test 2"

            android:summary="Some other preferences you can see.">

        <!-- Arbitrary key/value pairs can be included with a header as

             arguments to its fragment. -->

        <extra android:name="someKey" android:value="someHeaderValue" />

    </header>

 

    <header android:icon="@drawable/ic_3"

            android:title="Test Intent"

            android:summary="Launches an Intent.">

        <intent android:action="android.intent.action.VIEW"

                android:data="http://www.baidu.com/" />

    </header>

   

</preference-headers>

可看见1,在header中能够直接配置一个Fragment2,能够使用extra标签来,传递参数;3,可直接配置一个Intent  具体其它参数也不用多说了。

 MyHeadersPreferenceActivity

public class MyHeadersPreferenceActivity extends PreferenceActivity {

        

         @Override

         public void onBuildHeaders(List<Header> target) {

                   Log.i(TAG, "onBuildHeaders");

                   loadHeadersFromResource(R.xml.my_headers, target);

         }

        

         public static class MyFragmentTest1 extends PreferenceFragment {

            @Override

                  public void onCreate(Bundle savedInstanceState) {

                       super.onCreate(savedInstanceState);

           

                       // Load the preferences from an XML resource

                       addPreferencesFromResource(R.xml.my_fragmented1);

                  }

               }

        

         public static class MyFragmentTest2 extends PreferenceFragment {

                   @Override

                  public void onCreate(Bundle savedInstanceState) {

                       super.onCreate(savedInstanceState);

 

                       // Can retrieve arguments from headers XML.

                       Log.i(this.getClass().getSimpleName(), "Arguments: " + getArguments());

           

                       // Load the preferences from an XML resource

                       addPreferencesFromResource(R.xml.my_fragmented2);

                  }

              }

}

类比较简单,继承自Preferencectivity,重写onBuildHeaders方法,在此方法中加载headers。还有2Fragment类前边已经说过了,此处不表。

 

my_fragment1ed1.xml

<?xml version="1.0" encoding="utf-8"?>

<PreferenceScreen

        xmlns:android="http://schemas.android.com/apk/res/android">

    <CheckBoxPreference

            android:key="checkbox_preference_"

            android:title="Checkbox Test title"

            android:summary="Checkbox Test summary." />

</PreferenceScreen>

很简单,挺眼熟吧。

 从例子中,可以看出,Headers使用也比较简单。用它结合FragmentPreference来进行界面布局和用户交互操作很方便。

具体例子API Demo中有。