天天看點

Android Fragment 詳解 2016 幹貨

最近看了很多動畫和一些效果很好的自定義控件,發現了一件事,就是Android的View層設計思想和古老的JavaSwing是如此的相似。這是在原來的基礎上加入了一些輸入移動端的生命周期,使其在使用和性能上更好。但是對核心的了解還是可以借鑒一些的。

如果說Activity就是JavaSwing的JFrame那麼Fragment 就是在JPanel

一個是容器頂層控件,一個是顯示在容器上的中間層控件。

是以這裡插一句話,如果感覺自己android寫的不溜那麼就多看看java的代碼。和設計思想吧。android的東西太多都是繼承自java或者說就是java的衍生品。無論是頂層容器還是底層容器都是為了放互動容器的。

Fragment的使用

一、布局

大家完全可以把Fragment看成一個輕量級的Activity.為什麼輕量,因為他不用在mainfest.xml檔案中添加自己.第二他不能直接啟動,必須依附(attach)在activity之上。

是以在這布局這一塊,Fragment的使用完全可以和activity的布局劃等号,設計圖怎麼畫在這裡就怎麼設計一個 Fragment .

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:background="#00ff00" >  

    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="This is fragment 1"  
        android:textColor="#000000"  
        android:textSize="25sp" />  

</LinearLayout> 
           
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:background="#ffff00" >  

    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="This is fragment 2"  
        android:textColor="#000000"  
        android:textSize="25sp" />  

</LinearLayout>  
           

簡單的畫了兩個布局背景不同,文字區分1和2

二、在Activity中使用

使用方法一:靜态加載一個Fragment

第一步把這個 fragment執行個體化

public class Fragment1 extends Fragment {  

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        return inflater.inflate(R.layout.fragment1, container, false);  
    }  
}  
           

二和一 ,一樣

在onCreateView() 中實作的是

{
    View view=inflater.inflate(R.layout.fragment);//這個View就是父容器在這個布局裡的其他控件 好比TextView要依靠他findViewById();
    TextView tv=(TextView)view.findViewById(R.id,textview);
    return view;
}
           

這樣一個 Fragment在View層就建立成功了。

然後打開或建立activity_main.xml作為主Activity的布局檔案,在裡面加入兩個Fragment的引用,使用android:name字首來引用具體的

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:baselineAligned="false" >  

    <fragment  
        android:id="@+id/fragment1"  
        **android:name="com.example.fragmentdemo.Fragment1"**  
        android:layout_width="0dip"  
        android:layout_height="match_parent"  
        android:layout_weight="1" />  

    <fragment  
        android:id="@+id/fragment2"  
        **android:name="com.example.fragmentdemo.Fragment2"**  
        android:layout_width="0dip"  
        android:layout_height="match_parent"  
        android:layout_weight="1" />  

</LinearLayout>  
           

最後打開或建立MainActivity作為程式的主Activity,裡面的代碼非常簡單,都是自動生成的:

public class MainActivity extends Activity {  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
    }  

}  
           
Android Fragment 詳解 2016 幹貨

如我們的設計一樣,兩個Fragment平分了螢幕

使用方法二:動态添加

這回我們直接在Activity中使用Fragment

public class MainActivity extends Activity {  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        Display display = getWindowManager().getDefaultDisplay();  
        if (display.getWidth() > display.getHeight()) {  
            Fragment1 fragment1 = new Fragment1(); //建立Fragment
            getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit(); //添加Fragment送出
        } else {  
            Fragment2 fragment2 = new Fragment2();  
            getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment2).commit();  
        }  
    }   
}  
           

首先,我們要擷取螢幕的寬度和高度,然後進行判斷,如果螢幕寬度大于高度就添加fragment1,如果高度大于寬度就添加fragment2。動态添加Fragment主要分為4步:

1.擷取到FragmentManager,在Activity中可以直接通過getFragmentManager得到。

2.開啟一個事務,通過調用beginTransaction方法開啟。

3.向容器内加入Fragment,一般使用replace方法實作,需要傳入容器的id和Fragment的執行個體。

4.送出事務,調用commit方法送出。

現在運作一下程式,效果如下圖所示:

豎屏顯示結果

Android Fragment 詳解 2016 幹貨

橫屏顯示結果

Android Fragment 詳解 2016 幹貨

在實戰中主要使用的是第二種方法使用我們的Fragment.

Android Fragment 詳解 2016 幹貨

即底部是三個activity切換按鈕上面是三個Fragment這裡的,這裡對Fragment的使用方法就是使用動态加載的方法。

三、Fragment的生命周期 Fragment 就是一個輕量的Activity那麼他的聲明周期就和Activity非常像了。

生命周期如下:

1.onAttach() 在Fragment和Activity建立關聯的時候調用

2.onCreate() 初始化Fragment本身為inflate view做準備

3.onCreateView() 對布局中的所有控件進行初始化 綁定

4.onActivityCreated

5.onStart

6onResume

在按下home之後

1.onPause 程式挂起

2.onStop 目前activity 停止

在傳回程式之後

1.onStart 開始

2.onResume 恢複

點選back退出程式

1onPause

2onStop

3onDestoryView Fragment 的View被移除了。

4onDestory

5onDetach Fragment和Activiy解除關聯的時候調用

注:此處并沒有onRestart()方法!

三、Fragment通信

這裡的通信主要分為

fragment->fragment 通過getActivity()為橋梁進行通信

Activity->fragment

fragment-activity 最簡單 所有activity 之間的通信方法這種時候都可以用

如在之前Fragment2中添加一個button那麼我們需要調用其他相關的Fragment是如何實作的那。

public class Fragment2 extends Fragment {  

    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        return inflater.inflate(R.layout.fragment2, container, false);  
    }  

    @Override  
    public void onActivityCreated(Bundle savedInstanceState) {  
        super.onActivityCreated(savedInstanceState);  
        Button button = (Button) getActivity().findViewById(R.id.button);  
        button.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                TextView textView = (TextView) getActivity().findViewById(R.id.fragment1_text);  
                Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show();  
            }  
        });  
    }    
}  
           

當點選按鈕的時候就會在Toast中顯示Fragment1中的内容。

當然兩個Fragment需要使用一個共同的activity父容器。

最後分享一些使用心得

補充知識點:

1、什麼是FragmentTransaction?

使用Fragment時,可以通過使用者互動來執行一些動作,比如增加、移除、替換等。

所有這些改變構成一個集合,這個集合被叫做一個transaction。

可以調用FragmentTransaction中的方法來處理這個transaction,并且可以将transaction存進由activity管理的back stack中,這樣使用者就可以進行fragment變化的回退操作。

可以這樣得到FragmentTransaction類的執行個體:

ragmentManager  mFragmentManager = getSupportFragmentManager();
ragmentTransaction  mFragmentTransaction = mFragmentManager.beginTransaction();
           

在多個 Fragment 之間進行切換的時候

replace()和hide的差別

首先replace 是代替,之前的Fragment會被清空掉,在再次切換回來的時候會進行重新加載。而hide是将之前的一個fragment 進行隐藏,将新的fragment 疊在上面進行顯示.等在次調用的時候進行顯示。不需要重新加載。測試這個最簡單的方法就是 設計兩個fragment 在同一位置上放一個按鈕,一個有監聽一個沒有,但現實沒有監聽的按鈕點選按鈕的時候會響應一号按鈕的監聽事件。

另外一個對于 FragmentTransaction對象在commit之後就會失效。是以建議直接使用fragmentManager.beginTransaction() 這樣就不會産生失效的問題了。

commit 于commitAllowingStateLoss();的差別

簡單來說就是避免報錯。

他們都調用了commitInternal

public int commit() {

return commitInternal(false);

}

public int commitAllowingStateLoss() {

return commitInternal(true);

}

這個兩個方法差別就在傳參判斷後的處理方法checkStateLoss

當使用commit方法時,系統将進行狀态判斷,如果狀态(mStateSaved)已經儲存,将發生”Can not perform this action after onSaveInstanceState”錯誤。

如果mNoTransactionsBecause已經存在,将發生”Can not perform this action inside of ” + mNoTransactionsBecause錯誤