2012年12月6日 星期四

Android Fragments 的生命週期


當我們在寫Android程式時,程式的生命週期代表著這支程式的從出生、長大、老死的週期,這也代表著程式在每個階段都有屬於自己要執行的任務。
"第一支Android Fragment程式--HelloFragment"這篇文章介紹了基本的Fragments觀念,今天延續該篇繼續了解Fragments 的生命週期。
在前篇說到Fragment (碎片)不能獨立存在必須依附在Activity內,Fragment擁有自己的生命周期,但會受到Activity生命週期的約束。
所以,Fragment程式生命週期如下圖所示。

由於Fragment必須依附在Activity內,所以到底Activity與Fragment生命週期誰先執行,程式執行中哪個間點執行生命週期,以下用一個簡單的程式來討論。

程式碼主要是參考HelloFragment這篇文章的第一個範例:
程式專案:



程式碼:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:background="#FFFFFF"
        android:text="@string/hello_world"
        android:textColor="#0000FF" />

    <fragment
        android:id="@+id/first"
        android:name="edu.nkut.fragmenttest.MyFirstFragment"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_weight="2" />

</LinearLayout>

--------------------------------------------------------------------------------------------
firstfragment.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/Fragment1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#808080"
    android:gravity="center_vertical|center_horizontal"
    android:text="@string/my_fragment"
    android:textAppearance="?android:attr/textAppearanceLarge" />

--------------------------------------------------------------------------------------------
MainActivity.java

package edu.nkut.fragmenttest;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {
    static String Tag = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(Tag, "onCreate()............");
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(Tag, "onDestory()............");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(Tag, "onPause()............");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(Tag, "onResume()............");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(Tag, "onStart()............");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(Tag, "onStop()............");
    }

}
-
-------------------------------------------------------------------------------------------
MyFirstFragment.java

package edu.nkut.fragmenttest;

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;

public class MyFirstFragment extends Fragment {
    static String Tag = "Fragment";

    @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()............");
        View v = inflater.inflate(R.layout.firstfragment, container, false);
        return v;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.i(Tag, "onActivityCreate()............");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.i(Tag, "onDestroyView()............");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(Tag, "onDestroy()............");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.i(Tag, "onDetach()............");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.i(Tag, "onPause()............");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.i(Tag, "onResume()............");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.i(Tag, "onStart()............");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.i(Tag, "onStop()............");
    }

    @Override
    public void onAttach(Activity activity) {
        Log.i(Tag, "onAttach()............");
        super.onAttach(activity);
    }

}
--------------------------------------------------------------------------------------------

接著打開DDMS的 Logcat 來觀察程式的生命週期。

以下內容說明中,在Main Activity的Tag為MainActivity 用[M]代替,Fragment的Tag為Fragment用[F]代替。

1. 從下圖我們可以看到當Main Activity[M] 進入Fragment[F]時,整個程式生命週期執行的過程為:

[M]onCreate() --> [F]onAttach()--> [F]onCreate()--> [F]onCreateView()--> [F]onActivityCreate()--> [M]onStart() --> [F]onStart() --> [M]onResume() --> [F]onResume() -->開始執行Fragment程式內容。

2. 接著按下倒退鍵()離開程式,程式生命週期執行的過程為:

[F]onPause() --> [M]onPause() --> [F]onStop() --> [M]onStop() --> [F]onDestroyView() --> [F]onDestroy() --> [F]onDetach() --> [M]onDestroy() --> 程式結束。

3. 如果程式執行中按下Home鍵(),則程式生命週期執行的過程為:

[F]onPause() --> [M]onPause() --> [F]onStop() --> [M]onStop() -->返回Android系統主畫面
上述中Android系統主畫面指的是Android系統開機完成後所處的第一個畫面,並非程式的主畫面,由此得知如果按下Home鍵,程式並不會Destroy(銷毀)掉,這時程式一直在背景中執行。

4. 承第3步驟動作後,在返回Android系統主畫面後接著執行程式,這時候的生命週期過程為:

[M]onStart() --> [F]onStart() --> [M]onResume() --> [F]onResume() -->繼續執行Fragment程式。
這個部分補充一下,如果程式執行過程中進入休眠模式,當啟動解鎖後其生命週期跟上述週期一樣。

5. 另外當遇到螢幕旋轉方向時,我們可以看到程式會被Destroy(銷毀)掉,然後重新執行。整個生命週期就會是前述的第2點加上第1點。

6. 新版的 Android畫面多出了一個應用程式列表(),則程式生命週期執行的過程與第3點相同為:
[F]onPause() --> [M]onPause() --> [F]onStop() --> [M]onStop() -->進入程式列表
此時用手指滑動這支程式時會直接結束掉這隻程式的process,整個程式就像蒸發掉的感覺,由於是kill Process所以並不會執行Destroy等動作。

綜合上述,我們可以得到下圖結論:
參考:
1.Fragments
http://developer.android.com/guide/components/fragments.html (英文版)
http://leybreeze.com/blog/?p=902 (簡體中文版)






==============延伸閱讀=====================

1.第一支Android Fragment程式--HelloFragment
http://cheng-min-i-taiwan.blogspot.tw/2012/04/android-fragment-hellofragment.html

2.Android Fragments 的生命週期
http://cheng-min-i-taiwan.blogspot.tw/2012/12/android-fragments.html

3.Fragment間的資料傳遞
http://cheng-min-i-taiwan.blogspot.tw/2013/01/fragment.html

4.Fragment與Activity間的資料傳遞
http://cheng-min-i-taiwan.blogspot.tw/2013/02/fragmentactivity.html

5.Fragment子類別之ListFragment
http://cheng-min-i-taiwan.blogspot.tw/2013/02/fragmentlistfragment.html

6.Fragment子類別之DialogFragment
http://cheng-min-i-taiwan.blogspot.tw/2013/02/fragmentdialogfragment.html

7.Fragment子類別之PreferenceFragment
http://www.cheng-min-i-taiwan.blogspot.tw/2013/02/fragmentpreferencefragment.html

8.Fragment子類別之WebViewFragment
http://cheng-min-i-taiwan.blogspot.tw/2013/02/fragmentwebviewfragment.html

2 則留言:

  1. 你寫的這篇文章淺顯易懂,感謝!!!

    回覆刪除
  2. 您寫的這篇文章淺顯易懂,感謝。

    回覆刪除