Android的Fragment介绍
前言
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基类供我们继承:
- DialogFragment 也就是浮动在Activity上面的fragment,这种对话框可以供用户返回,便于管理,是google推荐的做法。
- ListFragment 就是包含ListView的Fragment,用来显示列表等。
- 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介绍的更多相关文章
- Android 进阶 Fragment 介绍和使用 (一)
Fragment概述 Fragment是activity的界面中的一部分或一种行为.你可以把多个Fragment们组合到一个activity中来创建一个多面界面并且你可以在多个activity中重用一 ...
- Android 进阶 Fragment 介绍和使用 (二)
管理fragment 因为FragmentManager的API是在Android 3.0,也即API level 11开始引入的,所以对于之前的版本,需要使用support library中的Fra ...
- Android之Fragment 基本介绍(转)
Fragment Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的 ...
- Android中Fragment和ViewPager那点事儿(仿微信APP)
在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...
- Android中Fragment与Activity之间的交互(两种实现方式)
(未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...
- Android中Fragment的两种创建方式
fragment是Activity中用户界面的一个行为或者是一部分.你可以在一个单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再使用.你可以认 ...
- 【Android】Fragment的简单笔记
被虐了,做某公司笔试时,发现自己连个Fragment的生命周期都写不详细.平时敲代码,有开发工具的便利,有网上各大神的文章,就算忘了也很容易的可以查到,但当要自己不借助外界,却发现自己似乎对该知识点并 ...
- GitHub上排名前100的Android开源库介绍(来自github)
本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍,至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果,然后过滤了 ...
- Android之Fragment(二)
本文主要内容 如何管理Fragment回退栈 Fragment如何与Activity交互 Fragment与Activity交互的最佳实践 没有视图的Fragment的用处 使用Fragment创建对 ...
随机推荐
- 夜色的 cocos2d-x 开发笔记 02
本章我们让飞机发射子弹,因此我们要写这样一个方法 子弹资源:欢迎下载 很详细的注释吧,现在有几个地方报错,.h文件里面一定要先声明 这里是本章所有的新方法,你可以一次声明全部,嗯,还有个报错应该是我们 ...
- JavaScript基础:比较运算符——==与 ===;!=与!==
var x=10, y="10", m=15 x==y;//返回true x===y;//返回false x!=y;//返回false x!==y;//返回true//同理cons ...
- 在C++Builder中定义事件的实现方法
++Builder是由Borland公司推出的一款可视化集成开发工具.C++Builder的集成开发环境(IDE)提供了一系列可视化快速应用程序开发(RAD)工具,让程序员可以很轻松地建立和管理自己的 ...
- Java I/O 工作机制(一) —— Java 的 I/O 类库的基本架构
Java 的 I/O 类库的基本架构 Java 的 I/O 操作类在包 java.io 下,有将近 80 个类. 按数据格式分类: 面向字节(Byte)操作的 I/O 接口:InputStream 和 ...
- JS回调函数(理解篇)
概述: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而 ...
- SVN建立分支、代码合并以及常用操作
在项目开发的过程中,现在遇到这样一个问题: 现在是9月份,在同一个项目中我要开发A.B两个模块,A模块是11月份上线,B模块是12月份上线,但是SVN上的trunk(主干)上的代码必须是上线的. 假设 ...
- 腾讯CodeStar第二季前端突击队腐蚀的画解法步骤笔记
所有题目地址:http://codestar.alloyteam.com/q2 本题内容:http://www.cnblogs.com/yedeying/p/3617593.html 腐蚀的画涉及到的 ...
- 经典的hash函数
unsigned int SDBMHash(char *str){ unsigned int hash = 0; while (*str) { // equivale ...
- [pytorch] Pytorch入门
Pytorch入门 简单容易上手,感觉比keras好理解多了,和mxnet很像(似乎mxnet有点借鉴pytorch),记一记. 直接从例子开始学,基础知识咱已经看了很多论文了... import t ...
- python 面向对象(一)--类(class)和实例(Instance)
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 ...