前言

fragment是从android3.0开始提出来的,用来支持大屏幕设备的ui设计。通过将activity划分为多个fragment,不仅提高了设计的灵活性,而且可以在程序运行时改变它们的特征,比如动态的修改,替换已有的fragment等等。

fragment的角色是相当于activity中ui的一个子集或者说是activity中的一个模块,可以通过组合多个fragment来构造一个多个面板的界面。由于fragment嵌入在activity中,因此它的生命周期受到activity的影响,一旦activity停掉,它里面所有的fragment也都会被摧毁。

可以在activity的布局文件中通过声明<fragment>标签来填充它的布局,同时也可以通过代码将它加到已经存在的ViewGroup中,因为fragment布局实际上就是ViewGroup的子树。

新建一个Fragment

首先需要了解的是fragment的生命周期,如下图所示:

可以看出调用的先后顺序是:

  • onCreate  这里可以用来初始化一些当fragment停掉时候你仍想保存的组件
  • onCreateView  这里可以用来绘制fragment的用户界面,因此必须返回一个view
  • onPause  当fragment被移走或者替换时调用,可以在这里commit changes

一般可以继承fragment类来创建自己的fragment,同时亦有几个有用的fragment基类供我们继承:

  1. DialogFragment  也就是浮动在Activity上面的fragment,这种对话框可以供用户返回,便于管理,是google推荐的做法。
  2. ListFragment  就是包含ListView的Fragment,用来显示列表等。
  3. PreferenceFragment  可以用来显示用户选项的设置。

一般来说,要创建Fragment,第一步就是创建一个Fragment的子类,并在onCrateView方法中填充布局:

public static class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
//resourceID,ViewGroup, whether the inflated layout should be
//attached to the ViewGroup during inflation
return inflater.inflate(R.layout.example_fragment, container, false);
}
}

第二步就是将fragment添加到activity中,可以在activity的布局文件中声明,如:

<?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>

这样一来,当创建activity的布局时,就会初始化每一个fragment,并且调用它们的onCreateView方法,获取fragment的布局,然后插入到ViewGroup下面。

除了使用布局文件之外,还可以用程序进行添加:

FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

前两行用来获取碎片事务FragmentTransaction,后三行用来添加一个fragment,add方法的第一个参数是要放置的ViewGroup,第二个参数是要添加的fragment。

Fragment的管理

通过fragmentManager可以做一下事情:

  • 获取fragment,通过findFragmentById或者findFragmentByTag
  • 将Fragment从栈中移除,通过popBackStack方法
  • 为back stack注册监听器

相信这里的细节还有很多,暂时先不介绍。

Fragment的事务

fragment的一大亮点就是可以动态增加,删除,替换fragment,而这是通过fragmentTransaction来实现的。一旦获取了事务的实例,就可以通过调用add,remove,replace方法完成上述功能,接下来通过commit方法提交事务就可以了。

// Create new fragment and transaction
Fragment 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 stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null); // Commit the transaction
transaction.commit();

除此之外还可以调用addToBackStack方法将fragment添加到back stack中,用户按下返回键时,就会跳到back stack顶部的fragment。调不调用它的区别在于,如果没有它,fragment被remove后就彻底销毁了,再也不能恢复,如果调用了它,fragment就不会销毁而是stop,这样就可以恢复,因为fragment的状态都被保存在了back stack上面。

commit方法的作用是调度到activity的主线程中执行,并且事务的提交必须要在onSaveInstanceState之前。

和Activity的通信

fragment也是可以和它所在的activity通信的,比如可以通过getActivity()方法得到所在的activity,相应的,activity也可以调用FragmentManager的findFragmentById方法获取某一个fragment的引用。

有时候需要在fragment和activity之间共享事件,如activity有一个fragment,是用来显示文章的列表的,当用户点击了某一项,activity需要检测到这个事件,同时更改另一个fragment从而显示出相应的文章内容。这时可以这么做,在fragment中定义事件监听的接口,然后让activity实现这个接口。然后,这个fragment就可以调用接口中的某些方法来通知activity了。fragment中可以在onAttach里面将activity强制转化为接口的实现类,从而确保能成功调用接口中的方法。

public static class FragmentA extends ListFragment {

    OnArticleSelectedListener mListener;
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
...
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Append the clicked item's row ID with the content provider Uri
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
// Send the event and Uri to the host activity
mListener.onArticleSelected(noteUri);
}
...
}

例子

该例子来源于api demo,用到了很典型的两个fragment,一个是TitlesFragment,用来显示一个列表,另一个是DetailsFragment,用来显示选中item的详细信息。此外,该程序还考虑到了屏幕的横竖屏问题,如果是竖屏的话,没有足够的地方显示第二个Fragment,就单独启动一个Activity。源码如下:

/**
* Demonstration of using fragments to implement different activity layouts.
* This sample provides a different layout (and activity flow) when run in
* landscape.
*/
public class FragmentLayout extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.fragment_layout);
} /**
* This is a secondary activity, to show what the user has selected
* when the screen is not large enough to show it all in one activity.
*/ public static class DetailsActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
} if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
} /**
* This is the "top-level" fragment, showing a list of items that the
* user can pick. Upon picking an item, it takes care of displaying the
* data to the user as appropriate based on the currrent UI layout.
*/ public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0; @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); // Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES)); // Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE; if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
} if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
} @Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
} @Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
} /**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index; if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true); // Check what fragment is currently shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index); // Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (index == 0) {
ft.replace(R.id.details, details);
} else {
ft.replace(R.id.a_item, details);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
} } else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
} /**
* This is the secondary fragment, displaying the details of a particular
* item.
*/ public static class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment(); // Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args); return f;
} public int getShownIndex() {
return getArguments().getInt("index", 0);
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
} ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());
int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
4, getActivity().getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);
text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
return scroller;
}
} }


Android的Fragment介绍的更多相关文章

  1. Android 进阶 Fragment 介绍和使用 (一)

    Fragment概述 Fragment是activity的界面中的一部分或一种行为.你可以把多个Fragment们组合到一个activity中来创建一个多面界面并且你可以在多个activity中重用一 ...

  2. Android 进阶 Fragment 介绍和使用 (二)

    管理fragment 因为FragmentManager的API是在Android 3.0,也即API level 11开始引入的,所以对于之前的版本,需要使用support library中的Fra ...

  3. Android之Fragment 基本介绍(转)

    Fragment Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的 ...

  4. Android中Fragment和ViewPager那点事儿(仿微信APP)

    在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...

  5. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  6. Android中Fragment的两种创建方式

    fragment是Activity中用户界面的一个行为或者是一部分.你可以在一个单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再使用.你可以认 ...

  7. 【Android】Fragment的简单笔记

    被虐了,做某公司笔试时,发现自己连个Fragment的生命周期都写不详细.平时敲代码,有开发工具的便利,有网上各大神的文章,就算忘了也很容易的可以查到,但当要自己不借助外界,却发现自己似乎对该知识点并 ...

  8. GitHub上排名前100的Android开源库介绍(来自github)

    本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍,至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果,然后过滤了 ...

  9. Android之Fragment(二)

    本文主要内容 如何管理Fragment回退栈 Fragment如何与Activity交互 Fragment与Activity交互的最佳实践 没有视图的Fragment的用处 使用Fragment创建对 ...

随机推荐

  1. 阻塞IO, 非阻塞IO, 同步IO,异步IO

    阻塞IO, 非阻塞IO, 同步IO,异步IO 介绍 先说明几个概念 用户空间与内核空间 为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间(内存)划分为两部分,一部分 ...

  2. megacli使用

    查看raid类型 /opt/RAID/MegaCli64 -ShowSummary -a0 System Operating System: Linux version 2.6.32-220.el6. ...

  3. Java问题定位之Java线程堆栈分析

    采用Java开发的大型应用系统越来越大,越来越复杂,很多系统集成在一起,整个系统看起来像个黑盒子.系统运行遭遇问题(系统停止响应,运行越来越慢,或者性能低下,甚至系统宕掉),如何速度命中问题的根本原因 ...

  4. Thymeleaf 随记

    一.基础写法: th:text='${数据}  ,其中text可以修改成其他,如href,value,class....看需求 <p th:text='${后台返回的数据}'>静态文本&l ...

  5. 5 - 文件I/O操作

    读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的 写文件 #打开data.txt,创建一个实例f f = open('data.txt','w') #向文件中写内容 f. ...

  6. 【js基础修炼之路】— 我理解的原型链

    提起原型链,大家并不陌生,但是对于新人来说一提到原型方面的东西就会比较懵.在我自一次面试的时候,面试官也给我提了这样的问题,当时就按照我的理解说了一些,但是很肤浅,在此我希望给刚入门的前端小伙伴聊一下 ...

  7. java——二叉树面试题

    import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util ...

  8. java集合框架——Set

    一.Set概述 Set集合的特点是元素不允许重复,而且是无序的(添加和取出的顺序不一致). Set接口中的方法和Collection接口中的方法几乎相同,略. Set接口下常用的两个类:HashSet ...

  9. IOS Git源代码管理工具

    .新建一个“本地仓库” $ git init .配置仓库 >告诉git你是谁 git config user.name lnj >告诉git怎么联系你 git config user.em ...

  10. 高精度水题(POJ2109)

    题目链接:http://poj.org/problem?id=2109 double 可以虽然可以表示10^-307~~~10^208,但是精确度只有16位,这个题有bug. #include < ...