android - Fragment
現在主流的App中,基本的架構也都是一個主頁,然後每個Tab項用Fragment做佈局,不同選項做切換,使用起來也方便。Google推薦用Fragment來代替Activity。
Fragment為何要用
Fragment是Android 3.0被引用的,主要目的是為了給大螢幕(如平板電腦)上更加動態和靈活的UI設計提供支援。通過將Activity佈局分成片段,可以在執行時修改Activity的外觀,並在由Activity管理的返回棧中留這些更改,如果僅僅只有Activity佈局,那是不夠的,不僅在手機上有一套佈局,同時在平板上還需要設計一套佈局,那樣維護起來也麻煩,Fragment的優勢是佈局在不同裝置上的適配。
除此之外,使用Fragment還有這麼幾方面優勢:
(1)程式碼複用。
因為一個Fragment可以被多個Activity巢狀,是模組化UI的良好元件。
(2)Activity用來管理Fragment,Fragment可以被Attach新增和Detach釋放。
(3)可控性
Fragment可以像普通物件那樣自由的建立和控制,傳遞引數更加容易和方便。
(4)Fragment是view controller,它們包含可測試,解耦業務模組。
Fragment是什麼?
可以理解為一個具有自己生命週期的控制元件,但又有自己處理輸入事件的能力,又必須依賴於Activity,能互相通訊和託管。
這張圖是Fragment生命週期和Activity生命週期對比圖,可以看到兩者還是有很多相似的地方,比如都有onCreate(), onStart(), onPause(), onDestroy()等待,因為Fragment是託管到Activity中的,所以多了兩個onAttach()和onDetach()。這裡講講與Activity生命週期不一樣的地方。
onAttach()
Fragment和Activity建立關聯的時候被呼叫。
onCreate()
系統會在建立Fragment時呼叫此方法,可以初始化一段資原始檔等待。
onCreateView()
系統會在Fragment首次繪製其使用者介面時呼叫此方法,要想為Fragment繪製UI,從該方法返回View必須是Fragment佈局的根檢視,如果Fragment未提供UI,可以返回null
onViewCreated()
在Fragment被繪製後,呼叫此方法,可以初始化控制元件資源。
onActivityCreated()
當Activity被渲染繪製出來後。
onPause()
系統將此方法作為使用者離開Fragment的第一個訊號(但並不總是意味此Fragment會被銷燬)進行呼叫。通常可以在此方法內確認在當前使用者會話結束後仍然有效的任何更改(因為使用者可能不會返回)。
onDestroyView()
Fragment中的佈局被移除時呼叫。
onDetach()
與Activity解除關聯的時候呼叫。
Fragment怎麼用?
1.靜態用法
(1)繼承Fragment,重寫onCreateView決定Fragment的佈局。
(2)在Activity中宣告此Fragment,就當和普通View一樣。
例子:
fragment1.xml
<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>
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
}
<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" />
</LinearLayout>
2.動態用法
上面僅僅是Fragment簡單用法,它真正強大部分是動態的新增到Activity中。
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();
getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();
}
}
}
(1)獲取到FragmentManager, 在Activity中可以直接通過getFragmentManager得到。
(2)開啟一個事務,通過呼叫beginTransaction方法開啟。
(3)向容器內加入Fragment,一般使用replace方法實現,需要傳入容積的id和Fragment的例項。
(4)提交事務。
Fragment通訊
Fragment可以通過getActivity()訪問Activity例項,並輕鬆執行在Activity佈局中查詢檢視等任務。
View listView = getActivity().findViewById(R.id.list);
同樣的,Activity也可以使用findFragmentById或findFragmentByTag獲取對Fragment的引用。
ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
在某些情況下,可能需要通過與Activity共享事件。例如,如果一個新聞應用的Activity有兩個Fragment,一個用於顯示文章列表(Fragment A),另一個用於顯示文章(B),那麼A必須在列表項被選定後告知Activity,以便它告知B顯示該文章。
public static class FragmentA extends ListFragment {
OnArticleSelectedListener mListener;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
//
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
mListener.onArticleSelected(noteUri);//使用者每次點選列表項時,會呼叫Activity,共享事件
//activity需要實現此介面
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
}