Step 2:实现Fragment指定调用类TitleFragment

系统执行setContentView(R.layout.fragment_basic)调用时,左边fragment指定了实现类,则调用该类TitleFragment。我们结合生命周期来进行学习。Fragment的生命周期看起来比Activity要复杂,因为它要处理与activity之间的关系。

Pro Android学习笔记(三八):Fragment(3):基础小例子-续_ide

onInflate()和onAttach()

Fragment可有一个view hierarchy,以之与用户互动。这个view层级可以根据XML布局文件被创建(inflated)或通过代码创建。view层级需要与activity关联,才能被用户看见。Fragment的最初的两个生命周期为onInflate和onAttach。

/* 左边fragment是list,和ListActivity一样,继承ListFragment */public class TitleFragment extends ListFragment{
    private FragmentBasicTest myActivity = null; 
     private int mCurCheckPosition = 0;  
      
     …... 略 …… 

     @Override //【2】在fragment与activity关联后调用onAttach()。由于右边fragment的具体实现在activity的showDetails()中实现,需要获取activity的对象。 当然也可以直接用getActivity()获取。    public void onAttach(Activity activity) {  
 showInfo("onAttach() is called. activity is " + activity); 
        showInfo("   getActivity() : " + getActivity());
        super.onAttach(activity);
         myActivity = (FragmentBasicTest)activity;     }



    @Override//【1】首先调用:在Activity调用setContentView()时,xml中有<fragment>时被调用。bundle存贮的是fragment的状态,并非初始化的值。一般而言,此时太早,还没有和activity关联,一般很少需要在此进行处理,除非我们需要处理fragment的属性或参数。在API的reference中,Fragment的主要lifecycle甚至没有将onInflate()列入,因此在实际编程中,会较少用到。    public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) { 
    

showInfo("onInfalte() is called");        showInfo("   activity : " + activity);
        showInfo("   getActivity() : " + getActivity()); //Fragment尚为关联activity
 showInfo("   attribute是fragment的属相,例如R.id.titles =  " + R.id.titles); 
        for(int i = 0 ; i< attrs.getAttributeCount() ; i ++){ 
             showInfo("    attribute " + i + " :" + attrs.getAttributeName(i) + " = " + attrs.getAttributeValue(i));
         } 
         showInfo("   bundle : " + savedInstanceState);
        super.onInflate(activity, attrs, savedInstanceState);
     } 

    private void showInfo(String s){ 
         Log.d("TitleFragment",s); 
     }     
 }

我们看看运行的logcat显示。我们可以看出,在activity调用setContentView时,先调用Flagment中的onflate(),然后调用onAttach()。在onInfalte()中可以读取到我们在xml文件中<fragment… >设置的属性。在后面实现右边的fragment中,由于布局文件中<fragment …>中并没有指定class属性,而是在代码中实现,故没有onInflate()状态。

与activity的关联:看到onInfalte()和onAttach()都可以获得activity对象,但是如果采用getActivity()来获取,则发现onInfalte()的阶段对处理UI太早,都不能关联到activity。

参数:在整个生命周期,可以通过getArguments()来获取参数,但是不能在与activity关联后进行setArgments(),只能在初始化极早的阶段,例如构造函数和onInflate()。

Pro Android学习笔记(三八):Fragment(3):基础小例子-续_UI_02

onCreate()和onCreateView()

@Override //【3】在创建fragment中进行初始化时调用。注意此处的bundle参数,是存储fragment的状态。如果我们要为fragment启动一个后台线程,可以考虑将代码放于此处。 

public void onCreate(Bundle savedInstanceState) {  
    showInfo("onCreate() is called. ");    super.onCreate(savedInstanceState);
 } 

@Override //【4】创建fragment,并返回fragment的view层次结构,用于对UI的设计。本例继承了ListFragment实现,由其生成ListView,它的资源ID是android.R.id.list1,或者可以通过getListView()来获取。我们在此不需要在进行特别的处理,仅用于跟踪生命周期。public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     showInfo("onCreateView() is called. ");    return super.onCreateView(inflater, container, savedInstanceState);}

onCreate()和onCreateView()都是在activity调用setContentView()时被调用。也就是activity上未完成onCreate(),因此不应该在此加入与activity的view相关的代码。而后面的生命周期这是在activity完成onCreate()之后调用的。

Pro Android学习笔记(三八):Fragment(3):基础小例子-续_ide_03

onActivityCreated()

onActivityCreated顾名思义,是在activity完成onCreate()后被调用。我们可以在此处理activity的其他UI操作,而其他的fragment已经与activity关联,我们可以进行相互间处理。这也是用户看到UI界面之前的最后一个状态,对于从saved状态中重新创建activity及fragment来讲是重要状态。

回想一下,在ListActivity中是在setContentView()后面进行Adapter的设置,因为setContentView已经提供了view层级,因此在fragment中具体设置list也放在fragment的onCreateView()之后的生命周期onActivityCreated()中执行。

@Override //【5】onActivityCreated()在activity完成onCreate()后执行,在此可以加入UI设计(onCreateView())之后,UI被用户看到之前的代码。     public void onActivityCreated(Bundle savedInstanceState) {  
         showInfo("onActivityCreated() is called.");
         super.onActivityCreated(savedInstanceState);        // 1)通过Adapter进行view和data的关联   (new ArrayAdapter<String>(getActivity(),    //注意:在ListFragment中不要直接和ListView(通过id或者getListView()获取)关联,而要用setListAdapter()
                 android.R.layout.simple_list_item_1, 
                 BooksInfo.TITLES)); 
         ListView lv = getListView(); 
         lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
         lv.setSelection(mCurCheckPosition); 
         //2)根据书名设置右边framgent UI。         myActivity.showDetails(mCurCheckPosition); 
     }

onStart()、onResume()、onPause()和onStop()

这几个状态和activty的相应状体相似,对应为可视,可互动,不可互动和不可视。和activity的生命周期图相对比,从不可视的后台回复到可视的前台的过程是onStop()—>onRestart()—>onStart()。而fragment为onStop()—>onStart()。

Pro Android学习笔记(三八):Fragment(3):基础小例子-续_生命周期_04

onDestroyView()、onDestroy和onDetach()

当fragment允许与view相关的资源释放时调用onDestroyView(),清空通过onCreateView()所返回的view。接着,onDestroy()进行最后fragment状态的清空。最后调用onDetach(),删除与activity的关联()。

Pro Android学习笔记(三八):Fragment(3):基础小例子-续_生命周期_05

与用户互动处理

@Override //当用户点击书名,在右边fragment中显示相关的内容。在ListFragment中可以直接通过回调函数onListItemClick来实现。

public void onListItemClick(ListView l, View v, int position, long id) { 
     mCurCheckPosition = position; 
     myActivity.showDetails(mCurCheckPosition); 
 }

本博文涉及的例子代码,可以在Pro Android学习:Fragment中下载。