Android Fragment 真正的完全解析(上)

Android Fragment 真正的完全解析(上),本文力求為大傢說明Fragment如何產生,什麼是Fragment,Fragment生命周期,如何靜態和動態的使用Fragment,Fragment回退棧,Fragment事務;以及Fragment的一些特殊用途,例如:沒有佈局的Fragment有何用處?Fragment如何與Activity交互?Fragment如何創建對話框?Fragment如何與ActionBar集成等等。

1、Fragment的產生與介紹

Android運行在各種各樣的設備中,有小屏幕的手機,超大屏的平板甚至電視。針對屏幕尺寸的差距,很多情況下,都是先針對手機開發一套App,然後拷貝一份,修改佈局以適應平板神馬超級大屏的。難道無法做到一個App可以同時適應手機和平板麼,當然瞭,必須有啊。Fragment的出現就是為瞭解決這樣的問題。你可以把Fragment當成Activity的一個界面的一個組成部分,甚至Activity的界面可以完全有不同的Fragment組成,更帥氣的是Fragment擁有自己的生命周期和接收、處理用戶的事件,這樣就不必在Activity寫一堆控件的事件處理的代碼瞭。更為重要的是,你可以動態的添加、替換和移除某個Fragment。

2、Fragment的生命周期

Fragment必須是依存與Activity而存在的,因此Activity的生命周期會直接影響到Fragment的生命周期。官網這張圖很好的說明瞭兩者生命周期的關系:

可以看到Fragment比Activity多瞭幾個額外的生命周期回調方法:
onAttach(Activity)
當Fragment與Activity發生關聯時調用。
onCreateView(LayoutInflater, ViewGroup,Bundle)
創建該Fragment的視圖
onActivityCreated(Bundle)
當Activity的onCreate方法返回時調用
onDestoryView()
與onCreateView想對應,當該Fragment的視圖被移除時調用
onDetach()
與onAttach相對應,當Fragment與Activity關聯被取消時調用
註意:除瞭onCreateView,其他的所有方法如果你重寫瞭,必須調用父類對於該方法的實現,

3、靜態的使用Fragment

嘿嘿,終於到使用的時刻瞭~~
這是使用Fragment最簡單的一種方式,把Fragment當成普通的控件,直接寫在Activity的佈局文件中。步驟:
1、繼承Fragment,重寫onCreateView決定Fragemnt的佈局
2、在Activity中聲明此Fragment,就當和普通的View一樣
下面展示一個例子(我使用2個Fragment作為Activity的佈局,一個Fragment用於標題佈局,一個Fragment用於內容佈局):
TitleFragment的佈局文件:
[html] view plain copy
print?

android:layout_width=“match_parent”
android:layout_height=“45dp”

android:background=“@drawable/title_bar”>

<imagebutton

  • android:id=“@+id/id_title_left_btn”</imagebutton
  • android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:layout_centerVertical=“true”

    android:layout_marginLeft=“3dp”

    android:background=“@drawable/showleft_selector”/>

    <textview

  • android:layout_width=“fill_parent”</textview
  • android:layout_height=“fill_parent”

    android:gravity=“center”

    android:text=“我不是微信”

    android:textColor=“#fff”

    android:textSize=“20sp”

    android:textStyle=“bold”/>

     

    
    
    
        
    
        
    
    

    TitleFragment [java] view plain copy

     

    print?

    packagecom.zhy.zhy_fragments;

    importandroid.app.Fragment;

    importandroid.os.Bundle;

    importandroid.view.LayoutInflater;

    importandroid.view.View;

    importandroid.view.View.OnClickListener;

    importandroid.view.ViewGroup;

    importandroid.widget.ImageButton;

    importandroid.widget.Toast;

     

    publicclassTitleFragmentextendsFragment

    {

    privateImageButtonmLeftMenu;

    @Override

    publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,

    BundlesavedInstanceState)

    {

    Viewview=inflater.inflate(R.layout.fragment_title,container,false);

    mLeftMenu=(ImageButton)view.findViewById(R.id.id_title_left_btn);

    mLeftMenu.setOnClickListener(newOnClickListener()

    {

    @Override

    publicvoidonClick(Viewv)

    {

    Toast.makeText(getActivity(),

    ”iamanImageButtoninTitleFragment!”,

    Toast.LENGTH_SHORT).show();

    }

    });

    returnview;

    }

    }
    同理還有ContentFragment的其佈局文件:[html] view plain copyprint?

    android:layout_width=“match_parent”
    android:layout_height=“match_parent”

    android:orientation=“vertical”>

    <textview

  • android:layout_width=“fill_parent”</textview
  • android:layout_height=“fill_parent”

    android:gravity=“center”

    android:text=“使用Fragment做主面板”

    android:textSize=“20sp”

    android:textStyle=“bold”/>

    
    
    
        
    
    

    [java] view plain copyprint?

    packagecom.zhy.zhy_fragments;

    importandroid.app.Fragment;

    importandroid.os.Bundle;

    importandroid.view.LayoutInflater;

    importandroid.view.View;

    importandroid.view.ViewGroup;

    publicclassContentFragmentextendsFragment

    {

     

    @Override

    publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,

    BundlesavedInstanceState)

    {

    returninflater.inflate(R.layout.fragment_content,container,false);

    }

    }
    MainActivity[java] view plain copyprint?

    packagecom.zhy.zhy_fragments;

    importandroid.app.Activity;

    importandroid.os.Bundle;

    importandroid.view.Window;

    publicclassMainActivityextendsActivity

    {

     

    @Override

    protectedvoidonCreate(BundlesavedInstanceState)

    {

    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);

    setContentView(R.layout.activity_main);

    }

     

    }

    package com.zhy.zhy_fragments;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Window;
    
    public class MainActivity extends Activity
    {
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
        }
    
    }
    

    Activity的佈局文件: [java] view plain copy

     

    print?

    xmlns:tools=”https://schemas.android.com/tools”

    android:layout_width=”match_parent”

    android:layout_height=”match_parent”>

     

    <fragment

  • android:id=”@+id/id_fragment_title”</fragment
  • android:name=”com.zhy.zhy_fragments.TitleFragment”

    android:layout_width=”fill_parent”

    android:layout_height=”45dp”/>

     

    <fragment

  • android:layout_below=”@id/id_fragment_title”</fragment
  • android:id=”@+id/id_fragment_content”

    android:name=”com.zhy.zhy_fragments.ContentFragment”

    android:layout_width=”fill_parent”

    android:layout_height=”fill_parent”/>

    
    
        
    
        
    
    

    是不是把Fragment當成普通的View一樣聲明在Activity的佈局文件中,然後所有控件的事件處理等代碼都由各自的Fragment去處理,瞬間覺得Activity好幹凈有木有~~代碼的可讀性、復用性以及可維護性是不是瞬間提升瞭~~~下面看下效果圖:[html] view plain copyprint?

    xmlns:tools=“https://schemas.android.com/tools”

    android:layout_width=“match_parent”

    android:layout_height=“match_parent”>

     

    <fragment

  • android:id=“@+id/id_fragment_title”</fragment
  • android:name=“com.zhy.zhy_fragments.TitleFragment”

    android:layout_width=“fill_parent”

    android:layout_height=“45dp”/>

     

    <include

  • android:id=“@+id/id_ly_bottombar”</include
  • android:layout_width=“fill_parent”

    android:layout_height=“55dp”

    android:layout_alignParentBottom=“true”

    layout=“@layout/bottombar”/>

    <framelayout<li>android:id=“@+id/id_content”</framelayout<li>

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    android:layout_above=“@id/id_ly_bottombar”

    android:layout_below=“@id/id_fragment_title”/>

     

    
    
        
    
        
    
        <framelayout android:id="@+id/id_content" android:layout_above="@id/id_ly_bottombar" android:layout_below="@id/id_fragment_title" android:layout_height="fill_parent" android:layout_width="fill_parent">
    
    </framelayout>

    底部四個按鈕的佈局就不貼瞭,到時看效果圖就明白瞭~~

    下面主Activity

    [java] view plain copy

     

    print?

    packagecom.zhy.zhy_fragments;

    importandroid.app.Activity;

    importandroid.app.FragmentManager;

    importandroid.app.FragmentTransaction;

    importandroid.os.Bundle;

    importandroid.view.View;

    importandroid.view.View.OnClickListener;

    importandroid.view.Window;

    importandroid.widget.LinearLayout;

     

    publicclassMainActivityextendsActivityimplementsOnClickListener

    {

    privateLinearLayoutmTabWeixin;

    privateLinearLayoutmTabFriend;

    privateContentFragmentmWeixin;

    privateFriendFragmentmFriend;

     

    @Override

    protectedvoidonCreate(BundlesavedInstanceState)

    {

    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);

    setContentView(R.layout.activity_main);

    //初始化控件和聲明事件

    mTabWeixin=(LinearLayout)findViewById(R.id.tab_bottom_weixin);

    mTabFriend=(LinearLayout)findViewById(R.id.tab_bottom_friend);

    mTabWeixin.setOnClickListener(this);

    mTabFriend.setOnClickListener(this);

    //設置默認的Fragment

    setDefaultFragment();

    }

    privatevoidsetDefaultFragment()

    {

    FragmentManagerfm=getFragmentManager();

    FragmentTransactiontransaction=fm.beginTransaction();

    mWeixin=newContentFragment();

    transaction.replace(R.id.id_content,mWeixin);

    transaction.commit();

    }

     

    @Override

    publicvoidonClick(Viewv)

    {

    FragmentManagerfm=getFragmentManager();

    //開啟Fragment事務

    FragmentTransactiontransaction=fm.beginTransaction();

    switch(v.getId())

    {

    caseR.id.tab_bottom_weixin:

    if(mWeixin==null)

    {

    mWeixin=newContentFragment();

    }

    //使用當前Fragment的佈局替代id_content的控件

    transaction.replace(R.id.id_content,mWeixin);

    break;

    caseR.id.tab_bottom_friend:

    if(mFriend==null)

    {

    mFriend=newFriendFragment();

    }

    transaction.replace(R.id.id_content,mFriend);

    break;

    }

    //transaction.addToBackStack();

    //事務提交

    transaction.commit();

    }

     

    }

    package com.zhy.zhy_fragments;
    
    import android.app.Activity;
    import android.app.FragmentManager;
    import android.app.FragmentTransaction;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.Window;
    import android.widget.LinearLayout;
    
    public class MainActivity extends Activity implements OnClickListener
    {
        private LinearLayout mTabWeixin;
        private LinearLayout mTabFriend;
    
        private ContentFragment mWeixin;
        private FriendFragment mFriend;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
    
            // 初始化控件和聲明事件
            mTabWeixin = (LinearLayout) findViewById(R.id.tab_bottom_weixin);
            mTabFriend = (LinearLayout) findViewById(R.id.tab_bottom_friend);
            mTabWeixin.setOnClickListener(this);
            mTabFriend.setOnClickListener(this);
    
            // 設置默認的Fragment
            setDefaultFragment();
        }
    
        private void setDefaultFragment()
        {
            FragmentManager fm = getFragmentManager();
            FragmentTransaction transaction = fm.beginTransaction();
            mWeixin = new ContentFragment();
            transaction.replace(R.id.id_content, mWeixin);
            transaction.commit();
        }
    
        @Override
        public void onClick(View v)
        {
            FragmentManager fm = getFragmentManager();
            // 開啟Fragment事務
            FragmentTransaction transaction = fm.beginTransaction();
    
            switch (v.getId())
            {
            case R.id.tab_bottom_weixin:
                if (mWeixin == null)
                {
                    mWeixin = new ContentFragment();
                }
                // 使用當前Fragment的佈局替代id_content的控件
                transaction.replace(R.id.id_content, mWeixin);
                break;
            case R.id.tab_bottom_friend:
                if (mFriend == null)
                {
                    mFriend = new FriendFragment();
                }
                transaction.replace(R.id.id_content, mFriend);
                break;
            }
            // transaction.addToBackStack();
            // 事務提交
            transaction.commit();
        }
    
    }
    

    可以看到我們使用FragmentManager對Fragment進行瞭動態的加載,這裡使用的是replace方法~~下一節我會詳細介紹FragmentManager的常用API。

    註:如果使用Android3.0以下的版本,需要引入v4的包,然後Activity繼承FragmentActivity,然後通過getSupportFragmentManager獲得FragmentManager。不過還是建議版Menifest文件的uses-sdk的minSdkVersion和targetSdkVersion都改為11以上,這樣就不必引入v4包瞭。

    代碼中間還有兩個Fragment的子類,ContentFragment上面已經見過,FriendFragment其實類似:

    [java] view plain copy

     

    print?

    packagecom.zhy.zhy_fragments;

    importandroid.app.Fragment;

    importandroid.os.Bundle;

    importandroid.view.LayoutInflater;

    importandroid.view.View;

    importandroid.view.ViewGroup;

    publicclassFriendFragmentextendsFragment

    {

     

    @Override

    publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,

    BundlesavedInstanceState)

    {

    returninflater.inflate(R.layout.fragment_friend,container,false);

    }

    }
     

  • 發佈留言

    發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *