Fragment
一、Fragment的概念和用法:
(一)、概念:
Fragment是在Android 3.0 (API level 11)开始引入新的API技术。
为了提高代码重用性和改善用户体验,我们将Activity中的UI组件进行
分组和模块化管理。这些分组后的UI组件就是Fragment。
一个Activity页面中可以包含多个Fragment模块,而同一个Fragment模块也
可以被多个Activity使用。每个Fragment有自己的布局,有自己的生命周期。
虽然Fragment拥有自己的生命周期,但因为Fragment必须被嵌入到Activity中使用,
因此Fragment的生命周期是受其Activity宿主的生命周期所控制的。当Activity暂停时,
该Activtiy内的所有Fragment都会暂停;当Activity被销毁时,该Activity内的所有Fragment都会被销毁。
(二)、Fragment要点:【重点】
1、Fragment作为Activity界面的一部分组成出现;
2、可以在一个Activity中同时出现多个Fragment,并且,一个Fragment亦可在多个Activity中使用;
3、在Activity运行过程中,可以添加、移除、替换、隐藏、显示Fragment(add()、remove()、replace()、hide()、show());
4、Fragment可以响应自己的输入事件,并且有自己的生命周期,当然,它们的生命周期直接受其所属的宿主Activity的生命周期控制。
5、FragmenetTransaction的方法:
使用add()加入fragment时将触发onAttach(),使用attach()不会触发onAttach()
使用replace()替换后会将之前的fragment的view从viewtree中删除
触发顺序:
detach()->onPause()->onStop()->onDestroyView()
attach()->onCreateView()->onActivityCreated()->onStart()->onResume()
使用hide()方法只是隐藏了fragment的view并没有将view从viewtree中删除,随后可用show()方法将view设置为显示
而使用detach()会将view从viewtree中删除,和remove()不同,此时fragment的状态依然保持着,在使用
attach()时会再次调用onCreateView()来重绘视图,注意使用detach()后fragment.isAdded()方法将返回 false,
在使用attach()还原fragment后isAdded()会依然返回false(需要再次确认)
执行detach()和replace()后要还原视图的话, 可以在相应的fragment中保持相应的view,
并在onCreateView()方法中通过view的parent的removeView()方法将view和parent的关联删除后返回
(三)、Fragment家族常用的API
1、Fragment常用的三个类:
android.app.Fragment 主要用于定义Fragment
android.app.FragmentManager 主要用于在Activity中操作Fragment
android.app.FragmentTransaction
2、获取FragmentManage的方式:
getFragmentManager() // v4中,getSupportFragmentManager
3、主要的操作都是FragmentTransaction的方法
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
transaction.add() 往Activity中添加一个Fragment
transaction.remove() 从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
transaction.replace() 使用另一个Fragment替换当前的,实际上就是remove()+add()的合体
transaction.hide() 隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
transaction.show() 显示之前隐藏的Fragment
transaction.detach() 会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护
transaction.attach() 重建view视图,附加到UI上并显示
transatcion.commit() 提交一个事务
fragment.isAdded() 判断一个Fragment是否已经被添加到事务中
二、Fragment生命周期:
(一)、Fragment基本状态:
1、活动状态:Resumed 当前Fragment位于前台,用户可见,可以获得焦点;
2、暂停状态: Paused 另一个Activity处于前台并拥有焦点, 但是该Fragment
所在的Activity仍然可见(前台Activity局部透明或者没有覆盖整个屏幕),不过不能获得焦点;
3、停止状态:Stopped
要么是宿主Activity已经被停止, 要么是Fragment从Activity被移除但被添加到回退栈中;
停止状态的Fragment仍然活着(所有状态和成员信息被系统保持着)。 然而, 它对用户不再可见, 并且如果Activity被销毁,它也会被销毁;
4、销毁状态:Destroyed 只能等待被回收。
(二)、Fragment生命周期:【重点】
方法 描述
onAttach(Activity)
当前Fragment与Activity关联,调用!
onCreate()
完成fragment的初始化创建
onCreateView()
创建并返回与当前fragment相关联的层次视图view
onActivityCreated()
主activity的onCreate()执行完后,该方法才执行
onStart()
fragment可见,当主activity处于started状态后执行
onResume()
fragment能与用户交互,当主activity处于resumed状态后执行
onPause()
fragment不在与用户交互,可能在主activity将要处于paused前执行,可能该fragment被修改
onStop()
fragment不在可见,可能在主activity将要处于stopped前执行,可能该fragment被修改
onDestroyView()
允许该fragment清理视图相关资源
onDestroy()
清理掉视图state信息
onDetach()
该fragment不在于activity关联
1、onAttach(): 当该Fragment被添加到Activity时被回调。该方法只会被调用一次;
2、onCreate(): 当创建Fragment时被回调。该方法只会被调用一次;
3、onCreateView():每次创建、绘制该Fragment的View组件时回调该方法,Fragment将会显示该方法返回的View 组件;
4、onActivityCreated(): 当Fragment的宿主Activity被启动完成后回调该方法;
5、onStart(): 启动Fragment时被回调;
6、onResume(): onStart()方法后一定会回调onResume()方法;
7、onPause(): 暂停Fragment时被回调;
8、onStop(): 停止Fragment时被回调;
9、onDestroyView(): 销毁该Fragment所包含的View组件时调用;
10、onDestroy(): 销毁Fragment时被回调。该方法只会被调用一次;
11、onDetach(): 将Fragment从Activity中删除、替换完成时调用该方法。
onDestroy()方法后一定会回调onDetach()方法。该方法只会被调用一次。
【备注:】其中大多数程序必须实现Fragment的三个回调方法分别为:
onCreate :系统创建Fragments 时调用,可做执行初始化工作或者当程序被暂停或停止时用来恢复状态,跟Activity 中的onCreate相当。
onCreateView :用于首次绘制用户界面的回调方法,必须返回要创建的Fragment 视图UI。假如你不希望提供Fragment用户界面则可以返回NULL。
onPause : 当用户离开这个Fragment的时候调用,这时你要提交任何应该持久的变化,因为用户可能不会回来。
(三)、示例代码:
1、Fragment的布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text_leftfragment_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是leftFragment中的textview"/>
</LinearLayout>
2、MainActivity的布局文件:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment_left_newstitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.steven.android24_fragmentlifecycle.LeftFragment"/>
</RelativeLayout>
3、Fragment文件中的java代码:
public class LeftFragment extends Fragment {
private static final String TAG = "LeftFragment";
@Override
public void onAttach(Activity activity) {
Log.i(TAG, "==onAttach()执行了");
super.onAttach(activity);
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "==onCreate()执行了");
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i(TAG, "==onCreateView()执行了");
// inflater.inflate(resource, null);
return inflater.inflate(R.layout.fragment_left, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "==onActivityCreated()执行了");
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
Log.i(TAG, "==onStart()执行了");
super.onStart();
}
@Override
public void onResume() {
Log.i(TAG, "==onResume()执行了");
super.onResume();
}
@Override
public void onPause() {
Log.i(TAG, "==onPause()执行了");
super.onPause();
}
@Override
public void onStop() {
Log.i(TAG, "==onStop()执行了");
super.onStop();
}
@Override
public void onDestroyView() {
Log.i(TAG, "==onDestroyView()执行了");
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.i(TAG, "==onDestroy()执行了");
super.onDestroy();
}
@Override
public void onDetach() {
Log.i(TAG, "==onDetach()执行了");
super.onDetach();
}
}
(四)、运行结果观察:
1、第一次加载Fragment:
2、在MainActivity中,点击“返回键”退出程序:
3、在MainActivity中,点击“HOME键”退出程序:
【备注:】请注意第二种和第三种情况的区别。如果点HOME键退出,则少调用了onDestroyView()、onDestroy()、onDetach()三个回调方法。
4、点击“下一页”,进入NextActivity页面:
5、在NextActivity页面中,点击“HOME键”退出程序:
6、上次HOME键退出后,重新进入程序:【因为上次是从NextActivity页面按HOME退出,所以此时直接进入 NextActivity页面 】
(五)、跟Fragment生命周期相关的其他方法:
1、onInflate():在onCreate()方法之前调用,这时窗体上的控件都没有被创建,
所以不能通过getActivity().findViewById(),因为此时getActivity()返回null。
2、onViewCreated():在onCreateView()方法后会立刻调用onViewCreated()方法。
通常在该方法中完成创建Fragment的最后工作,然后系统就开始调用onCreate()方法对窗体初始化。
三、创建Fragment:
(一)、创建Fragment的步骤:【只需要两步】
1、创建一个Fragment,必须继承Fragment 这个基类或其子类;
【备注:】除了继承基类 Fragment , 还有一些子类你可能会继承,是哪些子类呢?
DialogFragment
显示一个浮动的对话框. 用这个类来创建一个对话框,是使用在Activity类的对话框工具方法之外的一个好的选择,
因为你可以将一个fragment对话框合并到activity管理的fragment back stack中,
允许用户返回到一个之前曾被摒弃的fragment.
ListFragment
显示一个由一个adapter(例如 SimpleCursorAdapter)管理的项目的列表, 类似于ListActivity。
它提供一些方法来管理一个list view, 例如 onListItemClick()回调来处理点击事件.
2、实现回调方法:
Fragment类的代码看起来很像 Activity 。它包含了和activity类似的回调方法,
例如onCreate()、 onStart()、onPause()以及 onStop()。事实上,,
如果你准备将一个现成的Android应用转换到使用Fragment,可能只需要将代码从你的
Activity的回调方法中分别移动到你的Fragment的回调方法即可。
通常,应当至少实现如下的生命周期方法:
onCreate()
当创建fragment时, 系统调用该方法.
在实现代码中,应当初始化想要在fragment中保持的必要组件, 当fragment被暂停或者停止后可以恢复.
onCreateView()
fragment第一次绘制它的用户界面的时候, 系统会调用此方法. 为了绘制fragment的UI,
此方法必须返回一个View, 这个view是你的fragment布局的根view. 如果fragment不提供UI, 可以返回null.
onPause()
用户将要离开fragment时,系统调用这个方法作为第一个指示(然而它不总是意味着fragment将被销毁.) 。
在当前用户会话结束之前,通常应当在这里提交任何应该持久化的变化(因为用户有可能不会返回).
【备注:】对于大部分Fragment而言,通常实现三个回调方法即可。
但是实际开发中可以根据需要重写Fragment生命周期中的任意回调方法。
(二)、Fragment实例:(静态)
找到fragment
FragmentManager fragmentManager = getFragmentManager();
leftFragment = (LeftFragment) fragmentManager.findFragmentById(R.id.fragment_left_title);
leftFragment = (LeftFragment) fragmentManager.findFragmentByTag("leftFrag");
1、描述:以“ 影视介绍 ”为例,无需页面切换,点击左侧影视名称,在右侧区域显示影视内容介绍。
2、主页面布局及Fragment布局文件代码:
//activity_main.xml布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment
android:id="@+id/fragment_left_title"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:name="com.example.fragmentdemo.fragment.LeftFragment"/>
<fragment
android:id="@+id/fragment_right_detail"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="3"
android:name="com.example.fragmentdemo.fragment.RightFragment"/>
</LinearLayout>
//LeftFragment的布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/listView_fragment_left"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
//RightFragment的布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text_fragment_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请点击左侧列表"/>
</LinearLayout>
【备注:】
<fragment>标签的android:id 和 android:tag属性必须至少有一个,同一个xml文件中id或tag必须唯一;
<fragment>标签的class 和 android:name属性功能完全相同,使用其中任何一个即可。
3、LeftFragment核心代码:
public class LeftFragment extends Fragment {
private ListView listView_fragment_left;
private String[] arr_data = new String[] { "扫毒", " 功夫战斗机", "顶楼的大象", "狂爱恶徒",
"兽性窥视", "新金瓶梅" };
private TextView text_fragment_right;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_left, null);
listView_fragment_left = (ListView) view
.findViewById(R.id.listView_fragment_left);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, arr_data);
listView_fragment_left.setAdapter(adapter);
listView_fragment_left
.setOnItemClickListener(new OnItemClickListener() {
@Override
publicvoid onItemClick(AdapterView<?> parent, View view,
int position, long id) {
InputStream is;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String data = "";
try {
is = getActivity().getResources().getAssets()
.open("movie" + position + ".txt");
byte[] buffer = newbyte[1024];
int c = 0;
while ((c = is.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();
}
data = new String(baos.toByteArray(), "utf-8");
} catch (IOException e) {
e.printStackTrace();
}
TextView text_fragment_right = (TextView) getActivity()
.findViewById(R.id.text_fragment_right);
if (text_fragment_right != null) {
text_fragment_right.setText(data);
} else {
Intent intent = new Intent(getActivity(),
DetailActivity.class);
intent.putExtra("detail", data);
startActivity(intent);
}
}
});
return view;
}
}
4、平板和手机适配:
如果想在平板和手机中显示不同的效果。则可以新建布局目录:layout-sw600dp.
三、动态创建Fragment:
(一)、概念:
如果将Fragment写在布局文件中,那么就是静态创建fragment;如果没有在布局文件中写<fragment>标签,而是在java文件中通过实例化Fragment创建Fragment的方式就是动态创建Fragment。
(二)、动态创建Fragment的步骤:
1、步骤:
2、Activity布局文件代码:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_main_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="点击发送消息"/>
<!-- fragment
android:id="@+id/fragment_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.steven.android24_fragmentarguments.DetailFragment" /-->
<LinearLayout
android:id="@+id/layout_container_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
3、MainActivity文件代码:
FragmentManager manager = getFragmentManager();
DetailFragment fragment = new DetailFragment();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.layout_container_fragment, fragment, "content_fragment");
transaction.commit();
四、Activity与Fragment之间的数据交互:
(一)、Activity向Fragment传递数据:Arguments
1、做法:
可以通过Fragment.setArguments()方法向Fragment传递数据,并且通过getArguments()方法获取传递的数据。
2、MainActivity文件代码:
publicclass MainActivity extends Activity {
privatestaticfinal String TAG = "MainActivity";
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "==onCreate()执行");
FragmentManager manager = getFragmentManager();
DetailFragment fragment = new DetailFragment();
Bundle bundle = new Bundle();
bundle.putString("msg", "Hello Fragment!!!");
fragment.setArguments(bundle);
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.layout_container_fragment, fragment,
"content_fragment");
transaction.commit();
}
}
3、DetailFragment文件代码:
publicclass DetailFragment extends Fragment {
private TextView text_fragment_detail;
private Button button_fragment_get;
@Override
publicvoid onAttach(Activity activity) {
super.onAttach(activity);
Log.i("DetailFragment", "==onAttach()");
}
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater
.inflate(R.layout.fragment_detail, container, false);
text_fragment_detail = (TextView) view
.findViewById(R.id.text_fragment_detail);
button_fragment_get = (Button) view
.findViewById(R.id.button_fragment_get);
Bundle bundle = getArguments();
if (bundle != null) {
text_fragment_detail.setText(bundle.getString("msg"));
} else {
text_fragment_detail.setText("没有收到信息!");
}
return view;
}
}
4、注意事项:
Supply the construction arguments for this fragment. This can only be called before the fragment has been attached to its activity; that is, you should call it immediately after constructing the fragment. The arguments supplied here will be retained across fragment destroy and creation.
翻译:setArguments(bundle)为fragment提供构造的参数。它只能在fragment回调onAttach()方法之前调用。就是说,你应该在构造完fragment之后立刻调用它。提供的这些参数将在Fragment被销毁前一直保留。
在布局文件中使用<fragment>标签声明的Fragment(也就是静态生成的Fragment),都不能使用setArguments方法设置Bundle对象。
(二)、Fragment向宿主Activity回传信息:(Fragment回调机制)
1、原则:
Fragment类要尽量保证其独立性,Fragment类中不应该有访问其他Fragment和Activity中资源的代码,否则这个Fragment就不能在不改动代码的情况下用在其他地方。
如何让多个Fragment之间可以独立多次使用,而不是紧密地绑定到一起?通常的做法就是在Fragment类中编写一个接口,然后在该Fragment的宿主窗口类中实现该接口。这样Fragment与其宿主就实现了信息交互。
2、Fragment接口回调的步骤:(五步曲)
在Fragment文件中定义接口:OnItemClickedListener,定义抽象方法onClick(String info);
在Fragment文件中定义属性:private OnItemClickedListener mylistener;
在Fragment文件中的onAttach()方法中执行:mylistener = (OnItemClickedListener) getActivity();
在Fragment文件中,给某个控件增加监听器,在监听器中执行:mylistener.onClick(“需要传递的数据”);
将MainActivity实现OnItemClickedListener,重写onClick(String info)方法。参数就是Fragment传递的数据信息,在该方法中执行希望的逻辑操作。
3、DetailFragment的核心代码:
publicclass DetailFragment extends Fragment {
private TextView text_fragment_detail;
private Button button_fragment_get;
private Button button_fragment_send;
private OnItemClickedListener mylistener;
publicinterface OnItemClickedListener {
publicvoid onClick(String info);
}
@Override
publicvoid onAttach(Activity activity) {
super.onAttach(activity);
Log.i("DetailFragment", "==onAttach()");
if (getActivity() instanceof OnItemClickedListener) {
mylistener = (OnItemClickedListener) getActivity();
}
}
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater
.inflate(R.layout.fragment_detail, container, false);
text_fragment_detail = (TextView) view
.findViewById(R.id.text_fragment_detail);
button_fragment_get = (Button) view
.findViewById(R.id.button_fragment_get);
button_fragment_send = (Button) view
.findViewById(R.id.button_fragment_send);
button_fragment_get.setOnClickListener(new OnClickListener() {
@Override
publicvoid onClick(View v) {
Bundle bundle = getArguments();
if (bundle != null) {
text_fragment_detail.setText(bundle.getString("msg"));
} else {
text_fragment_detail.setText("没有收到信息!");
}
}
});
button_fragment_send.setOnClickListener(new OnClickListener() {
@Override
publicvoid onClick(View v) {
mylistener.onClick(“我是fragment传递给宿主的信息!");
}
});
return view;
}
}
4、MainActivity的核心代码:
publicclass MainActivity extends Activity implements OnItemClickedListener {
privatestaticfinal String TAG = "MainActivity";
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "==onCreate()执行");
FragmentManager manager = getFragmentManager();
DetailFragment fragment = new DetailFragment();
Bundle bundle = new Bundle();
bundle.putString("msg", "Hello Fragment!!!");
fragment.setArguments(bundle);
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.layout_container_fragment, fragment,
"content_fragment");
transaction.commit();
}
@Override
publicvoid onClick(String info) {
// 拿到Fragment传递过来的数据,显示在Title上。
// 实际项目中,我们是将Fragment_A传给宿主的信息拿到后,再通过setArguments()传递给Fragment_B。这样就实现了两个Fragment之间的数据传递。
setTitle(info);
}
}
五、FragmentManager与Fragment事务: 【重要】
(一)、概念:
Activity管理Fragment主要依靠FragmentManager。FragmentManager可以完成以下几方面的功能:
使用findFragmentById()或findFragmentByTag()方法来获取指定Fragment;
调用popBackStack()方法将Fragment从回退栈中弹出(如同用户按下“返回键”的效果);
调用addOnBackStackChangeListener()注册一个监听器,用于监听回退栈的变化情况。
在Activity中使用Fragment,一个很明显的特性是:根据用户的交互情况,可以对Fragment进行添加、移除、替换,以及执行其他动作,提交给Activity的每一套变化被称为一个事务。Fragment事务代表了Activity对Fragment执行的多个改变操作。实现事务借助于FragmentTransaction对象。我们可以保存每一个事务到一个Activity管理的backstack,这样用户就能由Fragment的变化返回导航。
(二)、Fragment与回退栈(导航):
1、回退栈的概念:BackStack
在Activity中已经探讨过回退栈,这种数据结构用来存放创建的窗口对象,并根据一定的规则决定哪些窗口对象应该出栈,凡是出栈的窗口对象将被销毁,也就是说窗口对象从入栈到出栈完成了窗口的整个生命周期。回退栈不仅能存储窗口对象,还可以存储Fragment对象。
(三)、FragmentManager与FragmentTransaction示例代码:
Fragment的布局文件:
// 构建Bundle对象,将文章id放在其中。
Bundle bundle = new Bundle();
bundle.putString("titleId", id);
// 构建文章内容的Fragment
RightFragment fragment = new RightFragment();
// 通过fragment对象的setArguments(bundle)方法将数据传输给其他Fragment。
fragment.setArguments(bundle);
// 通过getFragmentManager()方法构建FragmentManager对象
FragmentManager fragManager = getFragmentManager();
// 通过FragmentManager对象的beginTransaction()方法构建FragmentTransaction对象
FragmentTransaction trans = fragManager.beginTransaction();
// 将主页面布局文件中的ViewGroup容器替换成文章内容Fragment
trans.replace(R.id.fragment_content, fragment);
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// 将事务添加到回退栈,这样用户就可以通过“返回键”回到替换Fragment的上一个状态
trans.addToBackStack(null);
// 提交事务
trans.commit();
六、 FragmentTransaction中的replace方法与add、hide、show方法的区别:【重要】
示例代码如下:
private void initData() {
fragmentManager = getSupportFragmentManager();
// 初始化碎片集合
listFragments = new ArrayList<Fragment>();
listFragments.add(new FragmentOne());
listFragments.add(new FragmentTwo());
listFragments.add(new FragmentThree());
// 在指定位置默认加载第一个碎片
transaction = fragmentManager.beginTransaction();
transaction.add(R.id.layout_container, listFragments.get(0));
transaction.commit();
}
// 点击选项TAB按钮,执行碎片切换
public void clickButton(View view) {
switch (view.getId()) {
case R.id.button_one:
switchFragment(0);
break;
case R.id.button_two:
switchFragment(1);
break;
case R.id.button_three:
switchFragment(2);
break;
}
}
/*
* 使用replace()方法实现。 每次replace都会将当前的碎片进行销毁,新创建一个碎片将原有的进行替换
* 当TAB菜单切换到之前的选项时,虽然对应的碎片已经被创建过,但是因为销毁了而需要重新创建一次,因此会造成性能浪费
*/
private void replaceFragment(int tabindex) {
if (currentTabIndex != tabindex) {
transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.layout_container,
listFragments.get(tabindex));
transaction.addToBackStack(null);
transaction.commit();
currentTabIndex = tabindex;
}
}
/*
* 使用add()、hide()、show()方法实现。被加载出来的碎片在导航切换过程中不会被销毁,只是在隐藏和显示两个状态切换而已。
* 因为切换过的碎片不被销毁,自然会有内存占用上的开销,但是因为不用重新加载碎片而在性能上是优于replace的。
*/
private void switchFragment(int tabindex) {
if (currentTabIndex != tabindex) {
transaction = fragmentManager.beginTransaction();
// 定义当前碎片与即将加载的碎片
Fragment fromFragment = listFragments.get(currentTabIndex);
Fragment toFragment = listFragments.get(tabindex);
if (!toFragment.isAdded()) {
// 如果该碎片还没有被添加到事务中,则新添加到事务
transaction.hide(fromFragment).add(R.id.layout_container,
toFragment);
} else {
// 如果该碎片已经被添加到事务中,则从事务中取出该碎片进行显示即可。无需销毁再重新创建。
transaction.hide(fromFragment).show(toFragment);
}
// 提交执行过的事务
transaction.addToBackStack(null);
transaction.commit();
currentTabIndex = tabindex;
}
}
一、Fragment的概念和用法:
(一)、概念:
Fragment是在Android 3.0 (API level 11)开始引入新的API技术。
为了提高代码重用性和改善用户体验,我们将Activity中的UI组件进行
分组和模块化管理。这些分组后的UI组件就是Fragment。
一个Activity页面中可以包含多个Fragment模块,而同一个Fragment模块也
可以被多个Activity使用。每个Fragment有自己的布局,有自己的生命周期。
虽然Fragment拥有自己的生命周期,但因为Fragment必须被嵌入到Activity中使用,
因此Fragment的生命周期是受其Activity宿主的生命周期所控制的。当Activity暂停时,
该Activtiy内的所有Fragment都会暂停;当Activity被销毁时,该Activity内的所有Fragment都会被销毁。
(二)、Fragment要点:【重点】
1、Fragment作为Activity界面的一部分组成出现;
2、可以在一个Activity中同时出现多个Fragment,并且,一个Fragment亦可在多个Activity中使用;
3、在Activity运行过程中,可以添加、移除、替换、隐藏、显示Fragment(add()、remove()、replace()、hide()、show());
4、Fragment可以响应自己的输入事件,并且有自己的生命周期,当然,它们的生命周期直接受其所属的宿主Activity的生命周期控制。
5、FragmenetTransaction的方法:
使用add()加入fragment时将触发onAttach(),使用attach()不会触发onAttach()
使用replace()替换后会将之前的fragment的view从viewtree中删除
触发顺序:
detach()->onPause()->onStop()->onDestroyView()
attach()->onCreateView()->onActivityCreated()->onStart()->onResume()
使用hide()方法只是隐藏了fragment的view并没有将view从viewtree中删除,随后可用show()方法将view设置为显示
而使用detach()会将view从viewtree中删除,和remove()不同,此时fragment的状态依然保持着,在使用
attach()时会再次调用onCreateView()来重绘视图,注意使用detach()后fragment.isAdded()方法将返回 false,
在使用attach()还原fragment后isAdded()会依然返回false(需要再次确认)
执行detach()和replace()后要还原视图的话, 可以在相应的fragment中保持相应的view,
并在onCreateView()方法中通过view的parent的removeView()方法将view和parent的关联删除后返回
(三)、Fragment家族常用的API
1、Fragment常用的三个类:
android.app.Fragment 主要用于定义Fragment
android.app.FragmentManager 主要用于在Activity中操作Fragment
android.app.FragmentTransaction
2、获取FragmentManage的方式:
getFragmentManager() // v4中,getSupportFragmentManager
3、主要的操作都是FragmentTransaction的方法
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
transaction.add() 往Activity中添加一个Fragment
transaction.remove() 从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
transaction.replace() 使用另一个Fragment替换当前的,实际上就是remove()+add()的合体
transaction.hide() 隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
transaction.show() 显示之前隐藏的Fragment
transaction.detach() 会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护
transaction.attach() 重建view视图,附加到UI上并显示
transatcion.commit() 提交一个事务
fragment.isAdded() 判断一个Fragment是否已经被添加到事务中
二、Fragment生命周期:
(一)、Fragment基本状态:
1、活动状态:Resumed 当前Fragment位于前台,用户可见,可以获得焦点;
2、暂停状态: Paused 另一个Activity处于前台并拥有焦点, 但是该Fragment
所在的Activity仍然可见(前台Activity局部透明或者没有覆盖整个屏幕),不过不能获得焦点;
3、停止状态:Stopped
要么是宿主Activity已经被停止, 要么是Fragment从Activity被移除但被添加到回退栈中;
停止状态的Fragment仍然活着(所有状态和成员信息被系统保持着)。 然而, 它对用户不再可见, 并且如果Activity被销毁,它也会被销毁;
4、销毁状态:Destroyed 只能等待被回收。
(二)、Fragment生命周期:【重点】
方法 描述
onAttach(Activity)
当前Fragment与Activity关联,调用!
onCreate()
完成fragment的初始化创建
onCreateView()
创建并返回与当前fragment相关联的层次视图view
onActivityCreated()
主activity的onCreate()执行完后,该方法才执行
onStart()
fragment可见,当主activity处于started状态后执行
onResume()
fragment能与用户交互,当主activity处于resumed状态后执行
onPause()
fragment不在与用户交互,可能在主activity将要处于paused前执行,可能该fragment被修改
onStop()
fragment不在可见,可能在主activity将要处于stopped前执行,可能该fragment被修改
onDestroyView()
允许该fragment清理视图相关资源
onDestroy()
清理掉视图state信息
onDetach()
该fragment不在于activity关联
1、onAttach(): 当该Fragment被添加到Activity时被回调。该方法只会被调用一次;
2、onCreate(): 当创建Fragment时被回调。该方法只会被调用一次;
3、onCreateView():每次创建、绘制该Fragment的View组件时回调该方法,Fragment将会显示该方法返回的View 组件;
4、onActivityCreated(): 当Fragment的宿主Activity被启动完成后回调该方法;
5、onStart(): 启动Fragment时被回调;
6、onResume(): onStart()方法后一定会回调onResume()方法;
7、onPause(): 暂停Fragment时被回调;
8、onStop(): 停止Fragment时被回调;
9、onDestroyView(): 销毁该Fragment所包含的View组件时调用;
10、onDestroy(): 销毁Fragment时被回调。该方法只会被调用一次;
11、onDetach(): 将Fragment从Activity中删除、替换完成时调用该方法。
onDestroy()方法后一定会回调onDetach()方法。该方法只会被调用一次。
【备注:】其中大多数程序必须实现Fragment的三个回调方法分别为:
onCreate :系统创建Fragments 时调用,可做执行初始化工作或者当程序被暂停或停止时用来恢复状态,跟Activity 中的onCreate相当。
onCreateView :用于首次绘制用户界面的回调方法,必须返回要创建的Fragment 视图UI。假如你不希望提供Fragment用户界面则可以返回NULL。
onPause : 当用户离开这个Fragment的时候调用,这时你要提交任何应该持久的变化,因为用户可能不会回来。
(三)、示例代码:
1、Fragment的布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text_leftfragment_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是leftFragment中的textview"/>
</LinearLayout>
2、MainActivity的布局文件:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment_left_newstitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.steven.android24_fragmentlifecycle.LeftFragment"/>
</RelativeLayout>
3、Fragment文件中的java代码:
public class LeftFragment extends Fragment {
private static final String TAG = "LeftFragment";
@Override
public void onAttach(Activity activity) {
Log.i(TAG, "==onAttach()执行了");
super.onAttach(activity);
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "==onCreate()执行了");
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i(TAG, "==onCreateView()执行了");
// inflater.inflate(resource, null);
return inflater.inflate(R.layout.fragment_left, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "==onActivityCreated()执行了");
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
Log.i(TAG, "==onStart()执行了");
super.onStart();
}
@Override
public void onResume() {
Log.i(TAG, "==onResume()执行了");
super.onResume();
}
@Override
public void onPause() {
Log.i(TAG, "==onPause()执行了");
super.onPause();
}
@Override
public void onStop() {
Log.i(TAG, "==onStop()执行了");
super.onStop();
}
@Override
public void onDestroyView() {
Log.i(TAG, "==onDestroyView()执行了");
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.i(TAG, "==onDestroy()执行了");
super.onDestroy();
}
@Override
public void onDetach() {
Log.i(TAG, "==onDetach()执行了");
super.onDetach();
}
}
(四)、运行结果观察:
1、第一次加载Fragment:
2、在MainActivity中,点击“返回键”退出程序:
3、在MainActivity中,点击“HOME键”退出程序:
【备注:】请注意第二种和第三种情况的区别。如果点HOME键退出,则少调用了onDestroyView()、onDestroy()、onDetach()三个回调方法。
4、点击“下一页”,进入NextActivity页面:
5、在NextActivity页面中,点击“HOME键”退出程序:
6、上次HOME键退出后,重新进入程序:【因为上次是从NextActivity页面按HOME退出,所以此时直接进入 NextActivity页面 】
(五)、跟Fragment生命周期相关的其他方法:
1、onInflate():在onCreate()方法之前调用,这时窗体上的控件都没有被创建,
所以不能通过getActivity().findViewById(),因为此时getActivity()返回null。
2、onViewCreated():在onCreateView()方法后会立刻调用onViewCreated()方法。
通常在该方法中完成创建Fragment的最后工作,然后系统就开始调用onCreate()方法对窗体初始化。
三、创建Fragment:
(一)、创建Fragment的步骤:【只需要两步】
1、创建一个Fragment,必须继承Fragment 这个基类或其子类;
【备注:】除了继承基类 Fragment , 还有一些子类你可能会继承,是哪些子类呢?
DialogFragment
显示一个浮动的对话框. 用这个类来创建一个对话框,是使用在Activity类的对话框工具方法之外的一个好的选择,
因为你可以将一个fragment对话框合并到activity管理的fragment back stack中,
允许用户返回到一个之前曾被摒弃的fragment.
ListFragment
显示一个由一个adapter(例如 SimpleCursorAdapter)管理的项目的列表, 类似于ListActivity。
它提供一些方法来管理一个list view, 例如 onListItemClick()回调来处理点击事件.
2、实现回调方法:
Fragment类的代码看起来很像 Activity 。它包含了和activity类似的回调方法,
例如onCreate()、 onStart()、onPause()以及 onStop()。事实上,,
如果你准备将一个现成的Android应用转换到使用Fragment,可能只需要将代码从你的
Activity的回调方法中分别移动到你的Fragment的回调方法即可。
通常,应当至少实现如下的生命周期方法:
onCreate()
当创建fragment时, 系统调用该方法.
在实现代码中,应当初始化想要在fragment中保持的必要组件, 当fragment被暂停或者停止后可以恢复.
onCreateView()
fragment第一次绘制它的用户界面的时候, 系统会调用此方法. 为了绘制fragment的UI,
此方法必须返回一个View, 这个view是你的fragment布局的根view. 如果fragment不提供UI, 可以返回null.
onPause()
用户将要离开fragment时,系统调用这个方法作为第一个指示(然而它不总是意味着fragment将被销毁.) 。
在当前用户会话结束之前,通常应当在这里提交任何应该持久化的变化(因为用户有可能不会返回).
【备注:】对于大部分Fragment而言,通常实现三个回调方法即可。
但是实际开发中可以根据需要重写Fragment生命周期中的任意回调方法。
(二)、Fragment实例:(静态)
找到fragment
FragmentManager fragmentManager = getFragmentManager();
leftFragment = (LeftFragment) fragmentManager.findFragmentById(R.id.fragment_left_title);
leftFragment = (LeftFragment) fragmentManager.findFragmentByTag("leftFrag");
1、描述:以“ 影视介绍 ”为例,无需页面切换,点击左侧影视名称,在右侧区域显示影视内容介绍。
2、主页面布局及Fragment布局文件代码:
//activity_main.xml布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment
android:id="@+id/fragment_left_title"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:name="com.example.fragmentdemo.fragment.LeftFragment"/>
<fragment
android:id="@+id/fragment_right_detail"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="3"
android:name="com.example.fragmentdemo.fragment.RightFragment"/>
</LinearLayout>
//LeftFragment的布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/listView_fragment_left"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
//RightFragment的布局文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text_fragment_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请点击左侧列表"/>
</LinearLayout>
【备注:】
<fragment>标签的android:id 和 android:tag属性必须至少有一个,同一个xml文件中id或tag必须唯一;
<fragment>标签的class 和 android:name属性功能完全相同,使用其中任何一个即可。
3、LeftFragment核心代码:
public class LeftFragment extends Fragment {
private ListView listView_fragment_left;
private String[] arr_data = new String[] { "扫毒", " 功夫战斗机", "顶楼的大象", "狂爱恶徒",
"兽性窥视", "新金瓶梅" };
private TextView text_fragment_right;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_left, null);
listView_fragment_left = (ListView) view
.findViewById(R.id.listView_fragment_left);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, arr_data);
listView_fragment_left.setAdapter(adapter);
listView_fragment_left
.setOnItemClickListener(new OnItemClickListener() {
@Override
publicvoid onItemClick(AdapterView<?> parent, View view,
int position, long id) {
InputStream is;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String data = "";
try {
is = getActivity().getResources().getAssets()
.open("movie" + position + ".txt");
byte[] buffer = newbyte[1024];
int c = 0;
while ((c = is.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();
}
data = new String(baos.toByteArray(), "utf-8");
} catch (IOException e) {
e.printStackTrace();
}
TextView text_fragment_right = (TextView) getActivity()
.findViewById(R.id.text_fragment_right);
if (text_fragment_right != null) {
text_fragment_right.setText(data);
} else {
Intent intent = new Intent(getActivity(),
DetailActivity.class);
intent.putExtra("detail", data);
startActivity(intent);
}
}
});
return view;
}
}
4、平板和手机适配:
如果想在平板和手机中显示不同的效果。则可以新建布局目录:layout-sw600dp.
三、动态创建Fragment:
(一)、概念:
如果将Fragment写在布局文件中,那么就是静态创建fragment;如果没有在布局文件中写<fragment>标签,而是在java文件中通过实例化Fragment创建Fragment的方式就是动态创建Fragment。
(二)、动态创建Fragment的步骤:
1、步骤:
2、Activity布局文件代码:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_main_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickButton"
android:text="点击发送消息"/>
<!-- fragment
android:id="@+id/fragment_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="com.steven.android24_fragmentarguments.DetailFragment" /-->
<LinearLayout
android:id="@+id/layout_container_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
3、MainActivity文件代码:
FragmentManager manager = getFragmentManager();
DetailFragment fragment = new DetailFragment();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.layout_container_fragment, fragment, "content_fragment");
transaction.commit();
四、Activity与Fragment之间的数据交互:
(一)、Activity向Fragment传递数据:Arguments
1、做法:
可以通过Fragment.setArguments()方法向Fragment传递数据,并且通过getArguments()方法获取传递的数据。
2、MainActivity文件代码:
publicclass MainActivity extends Activity {
privatestaticfinal String TAG = "MainActivity";
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "==onCreate()执行");
FragmentManager manager = getFragmentManager();
DetailFragment fragment = new DetailFragment();
Bundle bundle = new Bundle();
bundle.putString("msg", "Hello Fragment!!!");
fragment.setArguments(bundle);
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.layout_container_fragment, fragment,
"content_fragment");
transaction.commit();
}
}
3、DetailFragment文件代码:
publicclass DetailFragment extends Fragment {
private TextView text_fragment_detail;
private Button button_fragment_get;
@Override
publicvoid onAttach(Activity activity) {
super.onAttach(activity);
Log.i("DetailFragment", "==onAttach()");
}
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater
.inflate(R.layout.fragment_detail, container, false);
text_fragment_detail = (TextView) view
.findViewById(R.id.text_fragment_detail);
button_fragment_get = (Button) view
.findViewById(R.id.button_fragment_get);
Bundle bundle = getArguments();
if (bundle != null) {
text_fragment_detail.setText(bundle.getString("msg"));
} else {
text_fragment_detail.setText("没有收到信息!");
}
return view;
}
}
4、注意事项:
Supply the construction arguments for this fragment. This can only be called before the fragment has been attached to its activity; that is, you should call it immediately after constructing the fragment. The arguments supplied here will be retained across fragment destroy and creation.
翻译:setArguments(bundle)为fragment提供构造的参数。它只能在fragment回调onAttach()方法之前调用。就是说,你应该在构造完fragment之后立刻调用它。提供的这些参数将在Fragment被销毁前一直保留。
在布局文件中使用<fragment>标签声明的Fragment(也就是静态生成的Fragment),都不能使用setArguments方法设置Bundle对象。
(二)、Fragment向宿主Activity回传信息:(Fragment回调机制)
1、原则:
Fragment类要尽量保证其独立性,Fragment类中不应该有访问其他Fragment和Activity中资源的代码,否则这个Fragment就不能在不改动代码的情况下用在其他地方。
如何让多个Fragment之间可以独立多次使用,而不是紧密地绑定到一起?通常的做法就是在Fragment类中编写一个接口,然后在该Fragment的宿主窗口类中实现该接口。这样Fragment与其宿主就实现了信息交互。
2、Fragment接口回调的步骤:(五步曲)
在Fragment文件中定义接口:OnItemClickedListener,定义抽象方法onClick(String info);
在Fragment文件中定义属性:private OnItemClickedListener mylistener;
在Fragment文件中的onAttach()方法中执行:mylistener = (OnItemClickedListener) getActivity();
在Fragment文件中,给某个控件增加监听器,在监听器中执行:mylistener.onClick(“需要传递的数据”);
将MainActivity实现OnItemClickedListener,重写onClick(String info)方法。参数就是Fragment传递的数据信息,在该方法中执行希望的逻辑操作。
3、DetailFragment的核心代码:
publicclass DetailFragment extends Fragment {
private TextView text_fragment_detail;
private Button button_fragment_get;
private Button button_fragment_send;
private OnItemClickedListener mylistener;
publicinterface OnItemClickedListener {
publicvoid onClick(String info);
}
@Override
publicvoid onAttach(Activity activity) {
super.onAttach(activity);
Log.i("DetailFragment", "==onAttach()");
if (getActivity() instanceof OnItemClickedListener) {
mylistener = (OnItemClickedListener) getActivity();
}
}
@Override
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater
.inflate(R.layout.fragment_detail, container, false);
text_fragment_detail = (TextView) view
.findViewById(R.id.text_fragment_detail);
button_fragment_get = (Button) view
.findViewById(R.id.button_fragment_get);
button_fragment_send = (Button) view
.findViewById(R.id.button_fragment_send);
button_fragment_get.setOnClickListener(new OnClickListener() {
@Override
publicvoid onClick(View v) {
Bundle bundle = getArguments();
if (bundle != null) {
text_fragment_detail.setText(bundle.getString("msg"));
} else {
text_fragment_detail.setText("没有收到信息!");
}
}
});
button_fragment_send.setOnClickListener(new OnClickListener() {
@Override
publicvoid onClick(View v) {
mylistener.onClick(“我是fragment传递给宿主的信息!");
}
});
return view;
}
}
4、MainActivity的核心代码:
publicclass MainActivity extends Activity implements OnItemClickedListener {
privatestaticfinal String TAG = "MainActivity";
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "==onCreate()执行");
FragmentManager manager = getFragmentManager();
DetailFragment fragment = new DetailFragment();
Bundle bundle = new Bundle();
bundle.putString("msg", "Hello Fragment!!!");
fragment.setArguments(bundle);
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.layout_container_fragment, fragment,
"content_fragment");
transaction.commit();
}
@Override
publicvoid onClick(String info) {
// 拿到Fragment传递过来的数据,显示在Title上。
// 实际项目中,我们是将Fragment_A传给宿主的信息拿到后,再通过setArguments()传递给Fragment_B。这样就实现了两个Fragment之间的数据传递。
setTitle(info);
}
}
五、FragmentManager与Fragment事务: 【重要】
(一)、概念:
Activity管理Fragment主要依靠FragmentManager。FragmentManager可以完成以下几方面的功能:
使用findFragmentById()或findFragmentByTag()方法来获取指定Fragment;
调用popBackStack()方法将Fragment从回退栈中弹出(如同用户按下“返回键”的效果);
调用addOnBackStackChangeListener()注册一个监听器,用于监听回退栈的变化情况。
在Activity中使用Fragment,一个很明显的特性是:根据用户的交互情况,可以对Fragment进行添加、移除、替换,以及执行其他动作,提交给Activity的每一套变化被称为一个事务。Fragment事务代表了Activity对Fragment执行的多个改变操作。实现事务借助于FragmentTransaction对象。我们可以保存每一个事务到一个Activity管理的backstack,这样用户就能由Fragment的变化返回导航。
(二)、Fragment与回退栈(导航):
1、回退栈的概念:BackStack
在Activity中已经探讨过回退栈,这种数据结构用来存放创建的窗口对象,并根据一定的规则决定哪些窗口对象应该出栈,凡是出栈的窗口对象将被销毁,也就是说窗口对象从入栈到出栈完成了窗口的整个生命周期。回退栈不仅能存储窗口对象,还可以存储Fragment对象。
(三)、FragmentManager与FragmentTransaction示例代码:
Fragment的布局文件:
// 构建Bundle对象,将文章id放在其中。
Bundle bundle = new Bundle();
bundle.putString("titleId", id);
// 构建文章内容的Fragment
RightFragment fragment = new RightFragment();
// 通过fragment对象的setArguments(bundle)方法将数据传输给其他Fragment。
fragment.setArguments(bundle);
// 通过getFragmentManager()方法构建FragmentManager对象
FragmentManager fragManager = getFragmentManager();
// 通过FragmentManager对象的beginTransaction()方法构建FragmentTransaction对象
FragmentTransaction trans = fragManager.beginTransaction();
// 将主页面布局文件中的ViewGroup容器替换成文章内容Fragment
trans.replace(R.id.fragment_content, fragment);
trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// 将事务添加到回退栈,这样用户就可以通过“返回键”回到替换Fragment的上一个状态
trans.addToBackStack(null);
// 提交事务
trans.commit();
六、 FragmentTransaction中的replace方法与add、hide、show方法的区别:【重要】
示例代码如下:
private void initData() {
fragmentManager = getSupportFragmentManager();
// 初始化碎片集合
listFragments = new ArrayList<Fragment>();
listFragments.add(new FragmentOne());
listFragments.add(new FragmentTwo());
listFragments.add(new FragmentThree());
// 在指定位置默认加载第一个碎片
transaction = fragmentManager.beginTransaction();
transaction.add(R.id.layout_container, listFragments.get(0));
transaction.commit();
}
// 点击选项TAB按钮,执行碎片切换
public void clickButton(View view) {
switch (view.getId()) {
case R.id.button_one:
switchFragment(0);
break;
case R.id.button_two:
switchFragment(1);
break;
case R.id.button_three:
switchFragment(2);
break;
}
}
/*
* 使用replace()方法实现。 每次replace都会将当前的碎片进行销毁,新创建一个碎片将原有的进行替换
* 当TAB菜单切换到之前的选项时,虽然对应的碎片已经被创建过,但是因为销毁了而需要重新创建一次,因此会造成性能浪费
*/
private void replaceFragment(int tabindex) {
if (currentTabIndex != tabindex) {
transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.layout_container,
listFragments.get(tabindex));
transaction.addToBackStack(null);
transaction.commit();
currentTabIndex = tabindex;
}
}
/*
* 使用add()、hide()、show()方法实现。被加载出来的碎片在导航切换过程中不会被销毁,只是在隐藏和显示两个状态切换而已。
* 因为切换过的碎片不被销毁,自然会有内存占用上的开销,但是因为不用重新加载碎片而在性能上是优于replace的。
*/
private void switchFragment(int tabindex) {
if (currentTabIndex != tabindex) {
transaction = fragmentManager.beginTransaction();
// 定义当前碎片与即将加载的碎片
Fragment fromFragment = listFragments.get(currentTabIndex);
Fragment toFragment = listFragments.get(tabindex);
if (!toFragment.isAdded()) {
// 如果该碎片还没有被添加到事务中,则新添加到事务
transaction.hide(fromFragment).add(R.id.layout_container,
toFragment);
} else {
// 如果该碎片已经被添加到事务中,则从事务中取出该碎片进行显示即可。无需销毁再重新创建。
transaction.hide(fromFragment).show(toFragment);
}
// 提交执行过的事务
transaction.addToBackStack(null);
transaction.commit();
currentTabIndex = tabindex;
}
}