Fragment是Android 3.0 新增加的部分,它的作用是将Activity拆分成多个完全独立封装的可重用的组件,每个组件都有它们的生命周期和UI布局。这样就可以为不同屏幕大小的设备创建动态灵活的UI。
一个Fragment必须被嵌入到一个Activity中,它的生命周期被其所属的宿主Acitivity的生命周期所影响。当Acitivity被暂停的时候,其中的所有Fragment被暂停,当Acitivity被销毁的时候,所有隶属于它的Fragment也将被销毁,当Acitivity处于Resumed状态的时候,可以单独得对每个Fragment进行添加或者删除操作。
和Activity不同的是Fragment不需要在Android Manifest文件中注册。

创建并添加Fragment

在layout文件夹下新建一个名为fragment1.xml的布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is fragment 1" />
</LinearLayout>

新建一个fragment2.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is fragment 2" />
</LinearLayout>

新建一个类Fragment1,这个类继承自Fragment

public class Fragment1 extends Fragment {  
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
}

新建一个类Fragment2 :

public class Fragment2 extends Fragment {  
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment2, container, false);
}
}

静态创建Fragment

然后打开或新建activity_main.xml作为主Activity的布局文件,在里面加入两个Fragment的引用,使用android:name前缀来引用具体的Fragment:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false" >
<fragment
android:id="@+id/fragment1"
android:name="com.example.fragmentdemo.Fragment1"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/fragment2"
android:name="com.example.fragmentdemo.Fragment2"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>

动态创建Fragment Fragment Manager

每个Activity都包含一个Fragment Manager来管理寄生于它的Fragment们,可以通过使用getFragmentManager方法来访问FragmentManger:

FragmentManager fragmentManager = getFragmentManager();

获得FragmentManager后可以做如下操作:

  1. 通过findFragmentById()或findFragmentByTag(),获取activity中的Fragment引用。
  2. 通过popBackStack()方法,从activity的后退栈中弹出fragment
  3. 通过addOnBackStackChangedListerner()注册一个侦听器监视后退栈的变化。
  4. 通过beginTransaction()获取FragmentTransaction。

Fragment Transaction 用来在Activity内添加,删除替换Fragment,使用Fragment Transaction 可以让布局成为动态。提交一组Fragment的变化叫做一个事务。事务通过FragmentTransaction来执行。还可以把每个事务保存在activity的后退栈中,这样就可以让用户在Fragment变化之间导航.

FragmentTransaction fragtransaction = fragmentManager.beginTransaction();
  • 添加Fragment

    fragmentsaction.add(用于存放flagment的容器ID,Fragment对象);
    //将Fragment对象添加到Fragment容器标签所指定的地方。
  • 删除Fragment

    Fragment fragment = fragmentManerger.findFragmentById(Fragment容器ID);
    fragmentsaction.remove(fragment);
  • 替换Fragment

    fragmentsaction.replace(用于存放flagment的容器ID,Fragment对象);
  • 当用户想要Back按键会返回到前一个布局,或者想要回滚到前一个已经执行的Transaction可以在调用commit方法前,调用addToBackStack将Fragment添加到back堆栈

    fragtransaction.addToBackStack(null);
  • 设置切换动画

    transaction.setTransition(FragmentTransaction.TRANSIT_ENTER_MASK);
    transaction.setCustomAnimations(enter, exit);
  • 提交事务

    fragtransaction.commit();

主界面布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</LinearLayout>
public class MainActivity extends Activity {  
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Display display = getWindowManager().getDefaultDisplay();
if (display.getWidth() > display.getHeight()) {
Fragment1 fragment1 = new Fragment1();
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();
} else {
Fragment2 fragment2 = new Fragment2();
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment2).commit();
}
}
}

Fragment生命周期与Activity生命周期

  • onAttach:当fragment和它的父activity有关联的时候被调用,在此处可以获取Activity的引用。为进一步初始化做准备。

  • onCreate:调用该方法来进行Fragment的初始化。与Activity不同Fragment UI不在onCreate方法中初始化。

  • onCreateView:一旦Fragment被创建,要创建它自己的用户界面的时候调用该方法,在里面主要完成创建或者填充Fragment UI的工作,获取它所包含的View的引用以及绑定到该View的数据,创建所需的Server和Timer。

  • onActivityCreated:一旦父Activity和Fragment的UI创建后,通知fragment activity已经创建完成,在这个方法中主要完成父Activity被初始化完成或者Fragment的View被完全填充后才能做的事情。要和父Activity的UI交互也要等到这个阶段。

  • onStart:使fragment对用户可见(基于包含它的activity已经启动了)

  • onResume:使fragment与用户可进行交互(基于包含它的activity已经处于resume状态)在这个方法中主要工作是恢复所有暂停的Fragment需要的UI更新,线程或进程。这些在非活动状态是处于暂停的。

  • onPause:fragment不再与用户进行交互,要么由于activity处于暂停态,要么由于在activity中一个fragment的操作正在被修改,需要暂停UI的更新,挂起线程或者暂停那些不需要更新的CPU的集中处理,由于调用这个方法后,进程可能被终止,所以要保存所有的编辑和状态改变信息。

  • onStop:fragment不再与用户可见,要么因为它的activity被停止,要么因为在activity中一个fragment的操作正在被修改,在这里暂停其余的UI更新,挂起线程或者暂停不需要的处理

  • onDestroyView: 当Fragment的View被分离的时候调用该方法,这里主要用于清除资源相关的View。

  • onDestroy: 在整个生命周期结束的时候调用该方法去做fragment状态的最终清理,包括清除所有的资源,包括线程和关闭数据库连接。

  • onDetach:当fragment与其父activity分离的时候调用该方法。

onPause:fragment不再与用户进行交互,要么由于activity处于暂停态,要么由于在activity中一个fragment的操作正在被修改,需要暂停UI的更新,挂起线程或者暂停那些不需要更新的CPU的集中处理,由于调用这个方法后,进程可能被终止,所以要保存所有的编辑和状态改变信息。
onStop:fragment不再与用户可见,要么因为它的activity被停止,要么因为在activity中一个fragment的操作正在被修改,在这里暂停其余的UI更新,挂起线程或者暂停不需要的处理
onDestroyView: 当Fragment的View被分离的时候调用该方法,这里主要用于清除资源相关的View。
onDestroy: 在整个生命周期结束的时候调用该方法去做fragment状态的最终清理,包括清除所有的资源,包括线程和关闭数据库连接。
onDetach:当fragment与其父activity分离的时候调用该方法。

内置的Fragment

  • DialogFragment
    对话框式的Fragments。可以把fragmentdialog并入到到activity的返回栈中,使用户能再返回到这个对话框。
  • ListFragment
    显示一个列表控件,就像ListActivity类,它提供了很多管理列表的方法,onListItemClick和setListAdapter等。
  • PreferenceFragment
    显示一个Preference对象组成的列表,类似PreferenceActivity,主要用来创建设置界面。

Fragment之间进行通信

通常情况下,Activity都会包含多个Fragment,这时会遇到多个Fragment之间如何进行通信的问题。

fragment1.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    >  
<TextView
android:id="@+id/fragment1_text"
android:text="This is fragment 1" />
</LinearLayout>

fragment2.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
android:orientation="vertical">
<TextView
android:text="This is fragment 2" />
<Button
android:id="@+id/button"
android:text="Get fragment1 text"
/>
</LinearLayout>
public class Fragment2 extends Fragment {  
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment2, container, false);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Button button = (Button) getActivity().findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
TextView textView = (TextView)
getActivity().findViewById(R.id.fragment1_text);
Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show();
}
});
}
}

兼容多种屏幕方案

创建窄屏主布局文件

打开或新建res/layout/activity_main.xml作为程序的主布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
tools:context=".MainActivity" >
<fragment
android:id="@+id/menu_fragment"
android:name="com.example.fragmentdemo.MenuFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>

创建宽屏主布局文件

在res目录下新建layout-large目录,然后这个目录下创建新的activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:baselineAligned="false"
tools:context=".MainActivity"
>
<fragment
android:id="@+id/left_fragment"
android:name="com.example.fragmentdemo.MenuFragment"
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1"
/>
<FrameLayout
android:id="@+id/details_layout"
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="3">
</FrameLayout>
</LinearLayout>

menu_fragment.xml文件
左边菜单面板的布局,这个是窄屏的第一个页面,用于触发两个子活动,宽屏的时候作为左面板

<?xml version="1.0" encoding="UTF-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="@+id/menu_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
></ListView>
</LinearLayout>


public class MenuFragment extends Fragment implements OnItemClickListener {  
private ListView menuList;
private ArrayAdapter<String> adapter;
private String[] menuItems = { "Sound", "Display" };
private boolean isTwoPane;
public void onAttach(Activity activity) {
super.onAttach(activity);
adapter = new ArrayAdapter<String>(activity, android.R.layout.simple_list_item_1, menuItems);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.menu_fragment, container, false);
menuList = (ListView) view.findViewById(R.id.menu_list);
menuList.setAdapter(adapter);
menuList.setOnItemClickListener(this);
return view;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity().findViewById(R.id.details_layout) != null) {
isTwoPane = true;
} else {
isTwoPane = false;
}
}
public void onItemClick(AdapterView<?> arg0, View view, int index, long arg3){
if (isTwoPane) {
Fragment fragment = null;
if (index == 0) {
fragment = new SoundFragment();
} else if (index == 1) {
fragment = new DisplayFragment();
}
getFragmentManager().beginTransaction().replace(R.id.details_layout, fragment).commit();
} else {
Intent intent = null;
if (index == 0) {
intent = new Intent(getActivity(), SoundActivity.class);
} else if (index == 1) {
intent = new Intent(getActivity(), DisplayActivity.class);
}
startActivity(intent);
}

}

sound_fragment.xml布局文件

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ff00"
android:orientation="vertical" >
<TextView
android:layout_centerInParent="true"
android:textSize="28sp"
android:textColor="#000000"
android:text="This is sound view"
/>
</RelativeLayout>

SoundFragment类

public class SoundFragment extends Fragment {  
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.sound_fragment, container, false);
return view;
}
}

display_fragment.xml布局文件

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0000ff"
android:orientation="vertical" >
<TextView
android:layout_centerInParent="true"
android:textSize="28sp"
android:textColor="#000000"
android:text="This is display view"
/>
</RelativeLayout>

DisplayFragment类

public class DisplayFragment extends Fragment {  
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.display_fragment, container, false);
return view;
}
}

sound_activity.xml

<?xml version="1.0" encoding="utf-8"?>  
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sound_fragment"
android:name="com.example.fragmentdemo.SoundFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</fragment>

SoundActivity

public class SoundActivity extends Activity {  
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sound_activity);
}
}

display_activity.xml

<?xml version="1.0" encoding="utf-8"?>  
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/display_fragment"
android:name="com.example.fragmentdemo.DisplayFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</fragment>

DisplayActivity类

public class DisplayActivity extends Activity {  
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.display_activity);
}
}

Fragment与Activity共享事件处理方法

在Fragment需要和主Activity共享和事件的地方,可以在Fragment中创建一个callback接口,主Acitivity来实现它:如下所示:

Public interface sharedFunction{
public void sharefun();
}

在Acitivity中实现后,在Fragment中可以如下访问:

sharedFunction shared = (sharedFunction )activity;
Shared. sharefun();
Contents
  1. 1. 创建并添加Fragment
  2. 2. 静态创建Fragment
  3. 3. 动态创建Fragment Fragment Manager
  4. 4. Fragment生命周期与Activity生命周期
  5. 5. 内置的Fragment
  6. 6. Fragment之间进行通信
  7. 7. 兼容多种屏幕方案
    1. 7.1. 创建窄屏主布局文件
    2. 7.2. 创建宽屏主布局文件
  8. 8. Fragment与Activity共享事件处理方法