Fragment学习

来源:互联网 发布:java程序员接私活经验 编辑:程序博客网 时间:2024/05/19 02:28
看了几篇关于Fragment的博客,将几篇整理了一下,以便学习。
http://blog.csdn.net/lmj623565791/article/details/37970961
http://www.tuicool.com/articles/zyYN3u
http://www.php100.com/html/it/biancheng/2015/0120/8419.html
http://www.cnblogs.com/mengdd/archive/2013/01/11/2856374.html

1、Fragment的产生与介绍
Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应平板神马超级大屏的。难道无法做到一个App可以同时适应手机和平板么,当然了,必须有啊。Fragment的出现就是为了解决这样的问题。你可以把Fragment当成Activity的一个界面的一个组成部分,甚至Activity的界面可以完全有不同的Fragment组成,更帅气的是Fragment拥有自己的生命周期和接收、处理用户的事件,这样就不必在Activity写一堆控件的事件处理的代码了。更为重要的是,你可以动态的添加、替换和移除某个Fragment。
2、Fragment生命周期

序号

方法名称

描述

1

public void onInflate(Activity activity, AttributeSet attrs,BundlesavedInstanceState)
 Activity.onCreate 方法之前调用,可以获取除了 View 之外的资源

2

public voidonAttach(Activity activity)

 f ragment 第一次与 Activity 产生关联时就会调用,以后不再调用

3

public voidonCreate(Bundle savedInstanceState)
 onAttach 执行完后会立刻调用此方法,通常被用于读取保存的状态值,获取或者初始化一些数据,但是该方法不执行,窗口是不会显示的,因此如果获取的数据需要访问网络,最好新开线程。

4

public ViewonCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState)
作用:创建 Fragment 中显示的 view, 其中inflater 用来装载布局文件, container 表示<fragment> 标签的父标签对应的 ViewGroup 对象,savedInstanceState 可以获取 Fragment 保存的状态

5

public void onViewCreated(View view, Bundle savedInstanceState)

继上面后就会调用此方法

6

public voidonActivityCreated(Bundle savedInstanceState)
 Activity.onCreate 方法调用后会立刻调用此方法,表示窗口已经初始化完毕,此时可以调用控件了

7

public voidonStart()

开始执行与控件相关的逻辑代码,如按键点击

8

public voidonResume()
这是 Fragment 从创建到显示的最后一个回调的方法

9

public voidonPause()

当发生界面跳转时,临时暂停,暂停时间是500ms ,0.5s 后直接进入下面的 onStop 方法

10

public voidonStop()
当该方法返回时, Fragment 将从屏幕上消失
 fragment不可见的, 可能情况:activity被stopped了 OR  fragment被移除但被加入到回退栈中
    一个stopped的fragment仍然是活着的如果长时间不用也会被移除

11

public voidonDestroyView()
 fragment 状态被保存,或者从回退栈弹出,该方法被调用

12

public voidonDestroy()
 Fragment 不再被使用时,如按返回键,就会调用此方法

13

public voidonDetach()

Fragment 生命周期的最后一个方法,执行完后将不再与 Activity 关联,将释放所有 fragment 对象和资源

3、详细解析

1,当首次展示布局页面时,其生命周期方法调用的顺序是:

\

2,而当关闭手机屏幕或者手机屏幕变暗时,其其生命周期方法调用的顺序是:

\

3,当再次对手机屏幕解锁或者手机屏幕变亮时,其生命周期方法调用的顺序是:

\

4,而当对当前Fragment所在屏幕按返回键时,其生命周期方法调用的顺序是:

1 01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onPause2 01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStop3 01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDestroyView4 01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDestroy5 01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDetach
5、addToBackStack在添加Fragment时如果没有调用addToBackStack方式的话,当FragmentManager更换Fragment时,是不保存Fragment的状态的。

首先,我们重写了两个Fragment,主要是重写了它们的生命周期方法,通过在其生命周期方法中打印出Log的方式来显示其方法的调用。

两个类分别是:

view sourceprint?
package com.yeepay.fraglifecircletest.frag;
 
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
 
import com.yeepay.fraglifecircletest.R;
 
public class FragA extends Fragment {
private static final String TAG = FragA.class.getSimpleName();
 
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.i(TAG, "onAttach");
}
 
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate");
}
 
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i(TAG, "onCreateView");
return inflater.inflate(R.layout.fragment_test_a, nullfalse);
}
 
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Log.i(TAG, "onViewCreated");
super.onViewCreated(view, savedInstanceState);
}
 
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
 
@Override
public void onDetach() {
Log.i(TAG, "onDetach");
super.onDetach();
}
 
@Override
public void onDestroyView() {
Log.i(TAG, "onDestroyView");
super.onDestroyView();
}
 
@Override
public void onStart() {
Log.i(TAG, "onStart");
super.onStart();
}
 
@Override
public void onStop() {
Log.i(TAG, "onStop");
super.onStop();
}
 
@Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
}
 
@Override
public void onPause() {
Log.i(TAG, "onPause");
super.onPause();
}
 
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "onActivityCreated");
super.onActivityCreated(savedInstanceState);
}
}
 
FragA.java
view sourceprint?
package com.yeepay.fraglifecircletest.frag;
 
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
 
import com.yeepay.fraglifecircletest.R;
 
public class FragB extends Fragment {
private static final String TAG = FragB.class.getSimpleName();
 
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.i(TAG, "onAttach");
}
 
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate");
}
 
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i(TAG, "onCreateView");
return inflater.inflate(R.layout.fragment_test_b, nullfalse);
}
 
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
Log.i(TAG, "onViewCreated");
super.onViewCreated(view, savedInstanceState);
}
 
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
 
@Override
public void onDetach() {
Log.i(TAG, "onDetach");
super.onDetach();
}
 
@Override
public void onDestroyView() {
Log.i(TAG, "onDestroyView");
super.onDestroyView();
}
 
@Override
public void onStart() {
Log.i(TAG, "onStart");
super.onStart();
}
 
@Override
public void onStop() {
Log.i(TAG, "onStop");
super.onStop();
}
 
@Override
public void onResume() {
Log.i(TAG, "onResume");
super.onResume();
}
 
@Override
public void onPause() {
Log.i(TAG, "onPause");
super.onPause();
}
 
@Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "onActivityCreated");
super.onActivityCreated(savedInstanceState);
}
}
 
FragB.java
当我们通过以下方式添加FragA时,
1 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
2 fragA = new FragA();
3 fragmentTransaction.replace(R.id.frag_container, fragA, fragNames[0]);
4 fragmentTransaction.commit();
它的生命周期展示方式是同在布局文件中静态设置的表现一模一样的,这里不再详细展开,大家可以查看一下以上内容。
当我们以如下方式展示FragA并且没有addToBackStack时,
view sourceprint?
@Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
switch (v.getId()) {
case R.id.button1:
if (fragA == null) {
fragA = new FragA();
fragmentTransaction.replace(R.id.frag_container, fragA, fragNames[0]);
//                    fragmentTransaction.addToBackStack(fragNames[0]);
else {
Fragment fragment = fragmentManager.findFragmentByTag(fragNames[0]);
fragmentTransaction.replace(R.id.frag_container, fragment, fragNames[0]);
}
break;
case R.id.button2:
if (fragB == null) {
fragB = new FragB();
fragmentTransaction.replace(R.id.frag_container, fragB, fragNames[1]);
//                    fragmentTransaction.addToBackStack(fragNames[1]);
else {
Fragment fragment = fragmentManager.findFragmentByTag(fragNames[1]);
fragmentTransaction.replace(R.id.frag_container, fragment, fragNames[1]);
}
break;
default:
break;
}
fragmentTransaction.commit();
}

FragA生命周期调用顺序是:

\

此时,如果再点击另外一个按钮B,将FragB展示出来,FragA和FragB的生命周期展示方式是:

\

可以看到,FragA调用顺序为onPause, onStop, onDestroyView, onDestroy, onDetach.这说明,FragA已经被FragmentManager完全抛弃了,取而代之的是FragB的完全展现。而如果此时按返回键的话,FragB的生命周期也将是onPause, onStop, onDestroyView, onDestroy, onDetach。这说明,在添加Fragment时如果没有调用addToBackStack方式的话,当FragmentManager更换Fragment时,是不保存Fragment的状态的。
下面我们在替换Fragment时顺便addToBackStack,则其生命周期展现方式是:
replace FragA and addToBackStack########################################################################################01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onAttach01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreate01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStart01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onResume

可以看得出来,此时的生命周期方法调用是跟没有addToBackStack时没有任何区别的。

然后通过点击按钮B,使用FragB来替换FragA,此时FragA和FragB的生命周期方法调用顺序是:

and then replace FragB and addToBackStack&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onPause01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStop01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDestroyView01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onAttach01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onCreate01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onCreateView01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onViewCreated01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onActivityCreated01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onStart01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onResume

由此可以看出,FragA生命周期方法只是调用到了onDestroyView,而onDestroy和onDetach则没有被调用,这说明FragA的界面已经被销毁了,但是FragmentManager并没有完全销毁FragA,FragA依然有状态保存在FragmentManager里面。

然后再点击按钮A,使用FragA来替换当前显示的FragB,此时FragA和FragB的生命周期方法调用顺序为:

and then replace FragA again&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onPause01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onStop01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onDestroyView01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStart01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onResume

可以看到,FragB的生命方法调用顺序是跟FragB替换FragA时FragA的调用顺序一致的,作用就是只销毁了视图,但是依然保留了Fragment的状态。而此时FragA的调用则值得注意,此时FragA直接从onCreateView调起,也就是说只是重新创建了视图,而依然使用上次被替换时的Fragment状态。

OK,说到此时,是否对Fragment的生命周期方法调用在是否addToBackStack时不同有所更加深入的了解了呢?

好吧,最后一个问题。是关于Fragment在FragmentManager管理时,show和hide时的生命周期方法调用。

此时的调用实现方式为:

view sourceprint?
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
switch (v.getId()) {
case R.id.button1:
hideAllFrags(fragmentTransaction);
if (fragA == null) {
fragA = new FragA();
fragmentTransaction.add(R.id.frag_container, fragA, fragNames[0]);
fragmentTransaction.addToBackStack(fragNames[0]);
else {
fragmentTransaction.show(fragA);
}
break;
case R.id.button2:
hideAllFrags(fragmentTransaction);
if (fragB == null) {
fragB = new FragB();
fragmentTransaction.add(R.id.frag_container, fragB, fragNames[1]);
fragmentTransaction.addToBackStack(fragNames[1]);
else {
fragmentTransaction.show(fragB);
}
break;
default:
break;
}
fragmentTransaction.commit();

细心的话可以发现,在展示Fragment时,我们使用了方法add而非上面用的replace。而且直接addToBackStack。其实这也可以理解,你想,FragmentManager在show或者hide时,肯定是已经存在的,或者如果没有的话,需要添加进来Fragment。这便是在show和hide时,需要注意的地方,即使用add和addToBackStack方法。

在点击按钮A时,FragA的调用顺序为:

01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onAttach01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onCreate01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStart01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onResume

可以看出没有什么不同于以上所言的部分。

然后,点击按钮B时,FragA和FragB的调用顺序为:

01-15 16:57:23.360    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags01-15 16:57:23.360    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onAttach01-15 16:57:23.360    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onCreate01-15 16:57:23.360    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onCreateView01-15 16:57:23.370    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onViewCreated01-15 16:57:23.370    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onActivityCreated01-15 16:57:23.370    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStart01-15 16:57:23.370    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onResume

可以看出,FragA并没有调用生命周期方法,这说明是展示FragB时,FragA的生命周期并没有发生变化。而FragB的生命周期与初次点击按钮A时FragA的生命周期方法相同。

然后再继续点击按钮A和B,此时打印出来的log为:

1 01-15 16:57:25.220    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags2 01-15 16:57:44.990    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags3 01-15 16:57:47.350    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags4 01-15 16:57:48.020    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags

这说明在FragA和FragB添加进BackStack之后无论如何地show或者hide,它们的生命周期不再发生变化。

而当屏幕上锁或变暗,然后再解锁或者变亮时,FragA和FragB的生命周期方法调用顺序为:

when screen is locked:###########################################################################################01-15 16:58:36.840    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onPause01-15 16:58:36.840    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onPause01-15 16:58:36.870    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStop01-15 16:58:36.880    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStopwhen screen is unlocked:##########################################################################################01-15 17:05:01.850    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStart01-15 17:05:01.850    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStart01-15 17:05:01.870    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onResume01-15 17:05:01.870    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onResume
可以看得出来,两个Fragment都调用了onPause, onStop, onStart, onResume。而且FragA的调用要在FragB之前,这说明跟他们添加进BackStack的顺序有关。
4、Fragment与Activity交互
一个Fragment的实例总是和包含它的Activity直接相关。
fragment可以通过getActivity() 方法来获得Activity的实例,然后就可以调用一些例如findViewById()之类的方法。
如:
  View listView = getActivity().findViewById(R.id.list);
但是注意调用getActivity()时,fragment必须和activity关联(attached to an activity),否则将会返回一个null。
相似的,activity也可以获得一个fragment的引用,从而调用fragment中的方法。
获得fragment的引用要用FragmentManager,之后可以调用findFragmentById() 或者 findFragmentByTag().
比如:
  ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
创建事件回调
一些情况下,可能需要fragment和activity共享事件,一个比较好的做法是在fragment里面定义一个回调接口,然后要求宿主activity实现它。
当activity通过这个接口接收到一个回调,它可以同布局中的其他fragment分享这个信息。
例如,一个新闻显示应用在一个activity中有两个fragment,一个fragment A显示文章题目的列表,一个fragment B显示文章。
所以当一个文章被选择的时候,fragment A必须通知activity,然后activity通知fragment B,让它显示这篇文章。
这个情况下,在fragment A中声明一个这样的接口OnArticleSelectedListener:
复制代码
public static class FragmentA extends ListFragment {    ...    // Container Activity must implement this interface    public interface OnArticleSelectedListener {        public void onArticleSelected(Uri articleUri);    }    ...}
 之后包含这个fragment的activity实现这个OnArticleSelectedListener接口,用覆写的onArticleSelected()方法将fragment A中发生的事通知fragment B。
为了确保宿主activity实现这个接口,fragment A的onAttach() 方法(这个方法在fragment 被加入到activity中时由系统调用)中通过将传入的activity强制类型转换,实例化一个OnArticleSelectedListener对象:
public static class FragmentA extends ListFragment {    OnArticleSelectedListener mListener;    ...    @Override    public void onAttach(Activity activity) {        super.onAttach(activity);        try {            mListener = (OnArticleSelectedListener) activity;        } catch (ClassCastException e) {            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");        }    }    ...}

  如果activity没有实现这个接口,fragment将会抛出ClassCastException异常,如果成功了,mListener将会是activity实现OnArticleSelectedListener接口的一个引用,所以通过调用OnArticleSelectedListener接口的方法,fragment A可以和activity共享事件。

  比如,如果fragment A是ListFragment的子类,每一次用户点击一个列表项目,系统调用fragment中的onListItemClick() 方法,在这个方法中可以调用onArticleSelected()方法与activity共享事件。

public static class FragmentA extends ListFragment {    OnArticleSelectedListener mListener;    ...    @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);    }    ...}
 
0 0
原创粉丝点击