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存在于Activity的ViewGroup中。
Settings模块使用PreferenceActivity
Settings模块主界面就是继承自PreferenceActivity,采用headers和fragment来显示。
public class Settings extends PreferenceActivity … { …. @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.settings_headers, target); …. } …. } |
显示界面使用PreferenceFragment
显示界面都是直接或简介继承自Fragment。比如:网络设置WirelessSettings继承自PreferenceFragment,PreferenceFragment是Fragment子类,我们可以根据不同需求来选择使用哪个Fragment,就像选择Activity和ListActivity一样。
①Fragment:你可以在onCreate方法中使用res/layout/xxx.xml文件,就像activity一样。
②PreferenceFragment:如果你显示的为列表,那么你就可以使用PreferenceFragment来实现,它里封装了ListView用作列表显示。其使用的布局文件为res/xml/xxx.xml
由上可知道Settings界面布局和架构。
例子:
使用fragment和view进行布局。
效果图:
采用相对布局,左边是一个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的生命周期也是类似的。Activity和fragment回调顺序如下:
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 暂停,那么所有在这个activity的fragments将被destroy释放。 你可以在activity的不同生命周期中,对fragment执行不同操作。
3,Fragment简单示例
自定义一个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中通过getFragmentManager来获得。FragmentManager 类一些主要的方法有通过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来获取嵌入到activity的fragment。
<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中能够直接配置一个Fragment;2,能够使用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。还有2个Fragment类前边已经说过了,此处不表。
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使用也比较简单。用它结合Fragment和Preference来进行界面布局和用户交互操作很方便。
具体例子API Demo中有。