Fragment学习

转载 2016年06月02日 10:39:02
看了几篇关于Fragment的博客,将几篇整理了一下,以便学习。

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 void onAttach(Activity activity)

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

3

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

4

public View onCreateView(LayoutInflater inflater, ViewGroup container,

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

5

public void onViewCreated(View view, Bundle savedInstanceState)

继上面后就会调用此方法

6

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

7

public void onStart()

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

8

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

9

public void onPause()

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

10

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

11

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

12

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

13

public void onDetach()

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

3、详细解析

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

\

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

\

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

\

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

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

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

两个类分别是:

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
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时,
@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﹕ onAttach
01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreate
01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView
01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated
01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated
01-13 17:08:43.359    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStart
01-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﹕ onPause
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStop
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onDestroyView
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onAttach
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onCreate
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onCreateView
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onViewCreated
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onActivityCreated
01-13 17:08:46.959    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onStart
01-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﹕ onPause
01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onStop
01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragB﹕ onDestroyView
01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView
01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated
01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated
01-13 17:08:51.869    3102-3102/com.yeepay.fraglifecircletest I/FragA﹕ onStart
01-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时的生命周期方法调用。

此时的调用实现方式为:

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﹕ hideAllFrags
01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onAttach
01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onCreate
01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onCreateView
01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onViewCreated
01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onActivityCreated
01-15 16:57:20.390    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStart
01-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﹕ hideAllFrags
01-15 16:57:23.360    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onAttach
01-15 16:57:23.360    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onCreate
01-15 16:57:23.360    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onCreateView
01-15 16:57:23.370    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onViewCreated
01-15 16:57:23.370    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onActivityCreated
01-15 16:57:23.370    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStart
01-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﹕ hideAllFrags
2 01-15 16:57:44.990    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags
3 01-15 16:57:47.350    9225-9225/com.yeepay.fraglifecircletest I/hideAllFrags﹕ hideAllFrags
4 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﹕ onPause
01-15 16:58:36.840    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onPause
01-15 16:58:36.870    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStop
01-15 16:58:36.880    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStop

when screen is unlocked:
##########################################################################################
01-15 17:05:01.850    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onStart
01-15 17:05:01.850    9225-9225/com.yeepay.fraglifecircletest I/FragB﹕ onStart
01-15 17:05:01.870    9225-9225/com.yeepay.fraglifecircletest I/FragA﹕ onResume
01-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);
    }
    ...
}
 

相关文章推荐

android之Fragment学习dome

  • 2016-09-27 17:43
  • 11.22MB
  • 下载

android学习手记第二章--Fragment 16 Mar,2011

Fragment可以理解成一个动作或者理解成在activity里面用户接口的一部分。在一个activity里面你可以加入多个fragment,或者在多个activity里面重复利用一个fragment...

android Fragment学习例子

  • 2014-09-17 16:16
  • 1.55MB
  • 下载

fragment学习。

  • 2013-12-04 20:46
  • 29KB
  • 下载

Fragment入门学习总结

1、继承Fragment,重写onCreateView决定Fragemnt的布局 2、在Activity中声明此Fragment,就当和普通的View一样 首先是布局文件:fragment1....

Android Fragment学习

  • 2015-04-23 17:07
  • 622KB
  • 下载

android ViewPager学习(五)Fragment里嵌套Viewpager的示例

目标: 在fragment内创建

fragment学习测试代码

  • 2014-04-29 11:05
  • 2.13MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)