Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android入門——Fragment詳解之基本概念與用法(一)

Android入門——Fragment詳解之基本概念與用法(一)

編輯:關於Android編程

引言

Android在3.0中引入了Fragments的概念,其目的是用在大屏幕設備上–例如平板電腦上,支持更加動態和靈活的UI設計。平板電腦的屏幕要比手機的大得多,有更多的空間來放更多的UI組件,並且這些組件之間會產生更多的交互。Fragment允許這樣的一種設計,而不需要你親自來管理 Viewhierarchy的復雜變化。 通過將Activity的布局分散到Fragment中, 你可以在運行時修改Activity的外觀,並在由Activity管理的back stack中保存那些變化。

一、Fragment概述

Android開發過程中,我們可以把Fragment想成Activity中的模塊,這個模塊有自己的布局,有自己的生命周期,單獨處理自己的輸入,在Activity運行的時候可以加載或者移除Fragment模塊。從一定程度上來說,與Web開發中的iframe和DIV布局思想有點類似。例像網易新聞、易車等應用程序將一個fragment放在左邊顯示文章列表,在右邊用另一個Fragment來顯示一篇文章——兩個Fragment在同一個Activity中並排著,並且每個Fragment都有其自己的生命周期回調方法序列用以處理各自的用戶輸入事件。因此,用戶可以在同一個Activity中選擇和閱讀文章,而不是在一個Activity中選擇,在另一個Activity中閱讀。這樣設計的好處就是當程序運行在平板尺寸屏幕設備上時,可以在Activity A中嵌入兩個Fragment。但是,當運行在手機尺寸屏幕上,就沒有足夠的空間容納兩個Fragment了,因此Activity A只能引用包含文章列表的Fragment,在當用戶選擇一篇文章時,可以啟動Activity B,它包含了用來閱讀文章的第二個fragment。這樣,應用程序通過以不同組合的復用fragments支持了平板電腦和手機,再比如官方的這個例子:
這裡寫圖片描述

二、Fragment的生命周期

因為Fragment必須嵌入在Acitivity中使用,所以Fragment的生命周期和它所在的Activity是密切相關的。如果Activity是暫停狀態,其中所有的Fragment都是暫停狀態;如果Activity是stop狀態,這個Activity中所有的Fragment都不能被啟動;如果Activity被銷毀,那麼它其中的所有Fragment都會被銷毀。但是,當Activity在活動狀態,可以獨立控制Fragment的狀態,比如加上或者移除Fragment。當這樣進行fragment transaction(轉換)的時候,可以把fragment放入Activity的back stack中,這樣用戶就可以進行返回操作。
這裡寫圖片描述

方法 功能說明 onAttach 在Fragment與Activity關聯之後被調用。雖然初始化Fragment參數可以通過getArguments()獲得,但當Fragment附加到Activity之後,就無法再調用setArguments()。so除了在最開始時,其它時間都無法向初始化參數添加內容 onCreate Fragment初次創建時調用。但此刻Activity還沒有創建完成,因為我們的Fragment也是Activity創建的一部分。所以當你嘗試在在這無法獲取Activity的一些資源 onCreateView 主要用於創建Fragment自身的UI,可用使用LayoutInflater對象的inflater()方法把布局xml映射為view,所以返回值必須是Fragment自身UI對應的view,但如果fragment沒有用戶界面可以返回null onActivityCreated 在Activity的OnCreate()結束後,會調用此方法。即此時Fragment和Activity均已創建完畢。所以我們可以在這個方法裡使用Activity的所有資源 onStart 當Fragment對用戶就是可見時,但用戶還未開始與Fragment交互。因為是與Activity的OnStart()綁定的。寫在Activity的OnStart()中處理的邏輯,換成用Fragment來實現時,依然可以放在OnStart()中來處理。 onResume 當Fragment對用戶可見並且正在運行時調用。即Fragment與用戶交互之前的最後一個回調。與onStart類似,也是與Activity的OnResume是相互綁定的,它依賴於包含它的Activity的Activity.onResume。當OnResume()運行完畢之後,就可以正式與用戶交互了 onPause 與Activity的OnPause()綁定,意義也一樣。當用戶離開Fragment時第一個調用這個方法(但並不總意味著Fragment將被銷毀)。按照經驗,當用戶結束會話之前,我們可以在這提交一些變化 onStop 與Activity綁定,已停止的Fragment可以直接返回到OnStart()回調,然後調用OnResume()。 onDestroyView 當Fragment將被結束或者保存,那麼下一個回調將是onDestoryView(),將會刪除在onCreateView創建的視圖。下次這個Fragment若要顯示,將會重新創建新視圖。這會在onStop之後和onDestroy之前調用。經測試這個方法的調用同onCreateView是否返回非null視圖無關。它會在的在這個視圖狀態被保存之後以及它被它的父Activity回收之前調用 onDestory 當Fragment不再使用時被調用。但即使調用了onDestroy()階段,仍可以從其依附的父Activity中找到,因為它還沒有Detach。 onDetach 當Fragment和Activity分離的時候調用,Fragment就不再與Activity相綁定,它也不再擁有視圖層次結構,它的所有資源都將被釋放

一旦Activity進入resumed狀態(也就是running狀態),我們就可以自由地添加和刪除Fragment了。因此,只有當Activity在resumed狀態時,Fragment的生命周期才能獨立的運轉,其它時候是依賴於Activity的生命周期變化的。

三、Fragment生命周期分析

1. 當創建Fragment時,它會經歷以下狀態.

onAttach()——>onCreate()——>onCreateView()——>
onActivityCreated()——>

2. 當Fragment對用戶可見的:

onStart()——>onResume()——>

3. 當Fragment進入“後台模式”的時:

onPause()——>onStop()——>

4. 當Fragment被銷毀了(或者持有它的Activity被銷毀了)時:

onPause()——>onStop()——>onDestroyView()——>onDestroy() ——>onDetach()——>

5. 與Activity一樣,在以下的狀態中,可以使用Bundle對象保存一個Fragment的對象。

onCreate()——>onCreateView()——>onActivityCreated()——>

四、Fragment的狀態

運行狀態:但Fragment處於前台,用戶可見,可獲取焦點 暫停狀態:其他Activity位於前台,該Fragment依然可以見,但不能獲取焦點 停止狀態:該Fragment完全不可見,失去焦點 銷毀狀態:該Fragment被完全刪除或所依附的Activity被結束。

五、Fragment的基本操作和使用

要使用Fragment,可通過繼承Fragment類,復寫相關方法來實現加載Fragment自身的UI並初始化Fragment相關變量,控制Fragment與Activity的交互,通常都需要指定一個UI,但也可以為Activity創建一個沒有UI只提供後台行為的Fragment。

1、創建Fragment分為:Java代碼動態創建xml靜態創建

1.1、xml靜態創建

首先在依附的Activity的布局文件中定義fragment節點(其中fragment節點裡的id和name必填,name對應著我們自定義的Fragment的子類的完整類名,還有一個tag屬性也應該是唯一的可以通過findFragmentByTag(tag)獲取對應的Fragement



    
     
    
再繼承Fragment重寫相關方法
package com.crazymo.fragmentsdemo;

import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by cmo on 16-4-19.
 */
public class MainFragment extends Fragment {
    private final String TAG="FramentDemo";
    @Override
    public void onAttach(Context context) {
        Log.d(TAG, "onAttach:剛剛與Activity對接");
        super.onAttach(context);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate:初始化Fragment對象");
        super.onCreate(savedInstanceState);

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView:初始化Fragment的UI");
        return inflater.inflate(R.layout.fragment_main, container, false);//參數依次為:布局id,依附的容器
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        Log.d(TAG, "onActivityCreated:Activity和Fragment都已經創建好了");
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.d(TAG, "onStart:Fragment變為可見,待交互");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.d(TAG, "onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.d(TAG, "onPause:與Activity的OnPause綁定");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.d(TAG, "onStop:與Activity的OnStop綁定");
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        Log.d(TAG, "onDestroyView:Fragment即將被保存或者刪除");
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy:還與Activity藕斷絲連中可以在Activity中找到");
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        Log.d(TAG, "onDetach:徹底和Activity分手了");
        super.onDetach();
    }
}
然後再定義Fragment自身的布局xml



    
    

接著在onCreatedView方法裡把布局xml映射為view並返回(一般通過Inflater對象的inflate(R.layout.fragment_main, container, false)方法)
return inflater.inflate(R.layout.fragment_main, container, false);//參數依次為:布局id,依附的容器

1.2、java代碼動態創建

getFragmentManager().beginTransaction().add(R.id.id_fragment_main,new MainFragment()).commit();//第一個參數為容器的Id,這裡為FrameLayout的Id,第二個參數為Fragment對象實例

getFragmentManager().beginTransaction().add(R.id.id_fragment_main,new MainFragment(),"MainFragment").commit();//第三個參數為tag
首先還是定義Fragemnt對應的布局文件和繼承Fragment實現自己的Fragment 然後在依附的Activity的布局文件中線使用FrameLayout占位
  
    <framelayout android:id="@+id/id_fragment_main" android:layout_height="match_parent" android:layout_width="match_parent">  
</framelayout>  
再獲取FragmentManager(在V4包中通過getSupportFragmentManager())
FrgamentManager fragmentManager=getFragmentManager();
通過beginTransaction方法開啟事務FragmentTransaction
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
使用FragmentTransactionadd或者replace方法向容器內添加Fragment(需要傳入容器的id和Fragment的實例對象。)
fragmentTrancsaction.add(id_fragment_main,new MainFragment());//容器的id,Fragment的實例對象
提交事務
fragmentTransaction.commit();

2、Fragment的刪除remove

Fragment的刪除也還是借助FragmentManager和FragmentTransaction,主要有兩個步驟:

先通過FragmentManager對象的findFragmentByIdfindFragmentByTag獲取對應的Fragment 再傳入到remove方法中,並commit。

3、Fragment的替換replace

Fragment的替換replace這個方法真的有點奇怪,並沒有像我們正常的邏輯,至少應該提供源Fragment和目標Fragment兩個參數,但並沒有只是提供了一個容器Id和目標Fragment(即將被添加到容器裡展示的Fragment),當年學習的時候也覺得很奇怪,這裡先不深究,以後再去分析。

fragmentManager.beginTransaction().replace(R.id.id_fragment_main,new OtherFragment()).commit();//容器Id,新的Fragment對象

4、Fragment的隱藏hide和顯示show

對於Fragment的hide或者show只需要傳遞我們一個將要hide或者show的Fragment即可。(需要注意的是無論是hide還是show都是針對頂層Fragment,也就是假設你要show的Fragment不是頂層的是show不出來的)

 private void hideFragment(String tag){
      Fragment mainFragment = fragmentManager.findFragmentByTag(tag);
 fragmentManager.beginTransaction().hide(mainFragment).addToBackStack(tag).commit();
  }
  private void showFragment(String tag){
      Fragment mainFragment = fragmentManager.findFragmentByTag(tag);  fragmentManager.beginTransaction().show(mainFragment).addToBackStack(tag).commit();
  }

5、Fragment 的attach和detach

public abstract FragmentTransaction attach(Fragment fragment); 它利用Fragment對象的onCreateView()來重建視圖,並重新把UI附著到fragment上(由於是將fragment添加到隊列,且只能添加到列隊頭部),所以attach()操作的結果是,最新操作的頁面始終顯示在最前面,此時調用fragment.isAdded()將返回True。
fragmentManager.beginTransaction().attach(mainFragment).addToBackStack(tag).commit();
public FragmentTransaction detach(Fragment fragment):與attach所做的工作相反,它將參數中的fragment與UI分離,此時的狀態與把fragment放入返回棧時一樣,雖然將view從viewtree中刪除,並將fragment從Activity的隊列中移除!但對應的fragment實例並不會刪除( 在使用detach()後,使用fragment.isAdded()返回的值是false),還是可以被fragmentManager管理的,所以通過FragmentManager.findViewByTag()仍然是會有值的。
fragmentManager.beginTransaction().detach(mainFragment).addToBackStack(tag).commit();

六、Fragment的基本應用完整例子

主布局的xml文件:



    <framelayout android:id="@+id/id_fragment_main" android:layout_height="0dp" android:layout_weight="1" android:layout_width="match_parent"></framelayout>

MainFragment的布局文件:



    
    

OtherFragment的布局文件:



    
    

MainActivity的代碼:

package com.crazymo.fragmentsdemo;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.nfc.Tag;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {
    private final String TAG="FramentDemo";
    private Button mAddBtn,mRemoveBtn,mRelpaceBtn,mHideBtn,mShowBtn;
    private FragmentManager fragmentManager=getFragmentManager();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "Activity onCreate");
        setContentView(R.layout.activity_main);
        init();
    }

    private void init(){
        getViews();
        setClickListener();
    }
    private void getViews(){
        mAddBtn= (Button) findViewById(R.id.id_addfragment_btn);
        mRelpaceBtn=(Button)findViewById(R.id.id_replacefragment_btn);
        mRemoveBtn= (Button) findViewById(R.id.id_removefragment_btn);
        mHideBtn= (Button) findViewById(R.id.id_hidefragment_btn);
        mShowBtn= (Button) findViewById(R.id.id_showfragment_btn);
    }

    private void setClickListener(){
        mAddBtn.setOnClickListener(this);
        mRemoveBtn.setOnClickListener(this);
        mRelpaceBtn.setOnClickListener(this);
        mHideBtn.setOnClickListener(this);
        mShowBtn.setOnClickListener(this);
    }

    @Override
    protected void onStart() {
        Log.d(TAG, "Activity onStart");
        super.onStart();
    }

    @Override
    protected void onRestart() {
        Log.d(TAG,"Activity onReStart");
        super.onRestart();
    }

    @Override
    protected void onResume() {
        Log.d(TAG,"Activity onResume");
        super.onResume();
    }

    @Override
    protected void onPause() {
        Log.d(TAG,"Activity onPause");
        super.onPause();
    }

    @Override
    protected void onStop() {
        Log.d(TAG,"Activity onStop");
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG,"Activity onDestory");
        super.onDestroy();
    }

    private void addFragemnt(@StringRes int viewGroupId,@NonNull Fragment fragment,String tag){
        fragmentManager=getFragmentManager();
        fragmentManager.beginTransaction().add(viewGroupId,fragment,tag)
                .addToBackStack(tag).commit();
    }
    private void removeFragment(String tag){
        Fragment fragment = fragmentManager.findFragmentByTag(tag);
        fragmentManager.beginTransaction().remove(fragment).commit();
    }
    private void replaceFragment(@StringRes int viewGroupId,@NonNull Fragment fragment){
        fragmentManager.beginTransaction().add(viewGroupId, fragment).commit();
    }
    private void hideFragment(String tag){
        Fragment mainFragment = fragmentManager.findFragmentByTag(tag);
        fragmentManager.beginTransaction().hide(mainFragment).addToBackStack(tag).commit();
    }
    private void showFragment(String tag){
        Fragment mainFragment = fragmentManager.findFragmentByTag(tag);
        fragmentManager.beginTransaction().show(mainFragment).addToBackStack(tag).commit();
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()){
            case R.id.id_addfragment_btn:
                int viewGroupId=R.id.id_fragment_main;
                addFragemnt(viewGroupId,new MainFragment(),"MainFragment");
                break;
            case R.id.id_removefragment_btn:
                removeFragment("MainFragment");
                break;
            case R.id.id_replacefragment_btn:
                //Fragment fragment2 = fragmentManager.findFragmentByTag("MainFragment");
              //fragmentManager.beginTransaction().remove(fragment2).commit();
                int viewGroup=R.id.id_fragment_main;
                replaceFragment(viewGroup,new OtherFragment());
                break;
            case R.id.id_hidefragment_btn:
                hideFragment("MainFragment");
                break;
            case R.id.id_showfragment_btn:
                showFragment("MainFragment");
                break;
            default:
                break;
        }
    }
}

MainFragment的代碼

package com.crazymo.fragmentsdemo;

import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by cmo on 16-4-19.
 */
public class MainFragment extends Fragment {
    private final String TAG="FramentDemo";
    @Override
    public void onAttach(Context context) {
        Log.d(TAG, "onAttach:剛剛與Activity對接");
        super.onAttach(context);

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate:初始化Fragment對象");
        super.onCreate(savedInstanceState);

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView:初始化Fragment的UI");
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        Log.d(TAG, "onActivityCreated:Activity和Fragment都已經創建好了");
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.d(TAG, "onStart:Fragment變為可見,待交互");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.d(TAG, "onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.d(TAG, "onPause:與Activity的OnPause綁定");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.d(TAG, "onStop:與Activity的OnStop綁定");
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        Log.d(TAG, "onDestroyView:Fragment即將被保存或者刪除");
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy:還與Activity藕斷絲連中可以在Activity中找到");
        super.onDestroy();
    }

    @Override
    public void onDetach() {
        Log.d(TAG, "onDetach:徹底和Activity分手了");
        super.onDetach();
    }
}

OtherFragment的代碼

package com.crazymo.fragmentsdemo;

import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by cmo on 16-4-21.
 */
public class OtherFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_other,null);
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved