PS:文章主要是博主自學源碼時記下來的新的筆記,很多東西都是自己的理解,不一定對,更不是教學文章。歡迎一起探討,不歡迎冷嘲熱諷,Thanks♪(・ω・)ノ~
源碼及API地址:https://developer.android.google.cn/reference/android/app/Fragment?hl=zh-cn
一、概況
頭部主要記住Fragment繼承自Object類,在Android3.0(API11)版本開始使用,在Android9.0(API28)被廢棄……(剛學就被廢了,真的sui~)
二、介紹
Fragment這個類是被放置在Activity中,用來充當用戶界面或者行爲的一個小碎片。各個Fragment之間是通過FragmentManager來相互聯繫的,而FragmentManager是通過Activity或者Fragment類中的getFragmentManager()方法獲取得到的。
Fragment這個類可以通過很多途徑達到各種各樣的效果。它的核心在一個運行較大的Activity的特殊操作或者界面中得以體現(意思就是當一個Activity越大Fragment在其中越能體現出它的價值)。Fragment類是緊密依附於Activity的,不能單獨運行。儘管Fragment有自己的生命週期,但是也要受到Activity的影響:比如當Activity停止運行時(就是onStop()唄),Activity中的所有Fragment也就都無法啓動,又比如當Activity被銷燬時(就是onDestory()唄),那麼這個Activity所包含的所有Fragment也要統統被銷燬。
所有的Fragment的子類必須要包含一個無參的構造函數,因爲在運行環境中當一個類需要被重新實例化時,尤其是恢復階段,就需要尋找這個無參的構造函數才能進行實例化,如果沒有找到,就會在一些恢復階段報RuntimeException異常;
三、內容
從四個方面進行介紹:
1.Older Platforms
就是說Fragment在Android3.0,HONEYCOMB這個版本被提出來的,對更早的版本可以用FragmentActivity進行兼容;
2.Lifecycle
儘管Fragment的生命週期依附在所屬的Activity中,但也有自己獨有的生命週期。包括像Activity的一些基本的生命週期比如“onResume()”,Fragment與Activity的交互、對UI的生成同意很重要。(這段沒太看懂,反正是爲了說明Fragment有着自己的生命週期,並且這些週期與Activity交互以及UI有關聯)
下面闡述Fragment生命週期:
文檔把生命週期分成了兩塊,一塊是綁定創建Fragment,一塊是銷燬解綁Fragment;
用一張圖片表示:
onAttach():Fragment與Activity關聯時調用;
onCreate():初始化Fragment調用;
onCreateView():Fragment綁定UI視圖調用;
onActivityCreated():Fragment在依賴的Activity的onCreate()返回後調用;
onStart():顯示Fragment界面視圖;
onResume():正常運行時,與用戶交互;
onPause():Fragment長時間不交互,或者依賴的Activity被Pause了,或者被一個Fragment通過修改時;
onStop():Fragment長時間不可見,或者依賴的Activity被Stop了,或者被一個Fragment通過修改時;
onDestoryView():當綁定了Fragment的UI視圖被移除時調用;
onDestory():最終的清理;
onDetach():與Activity解綁時調用;
PS:onDestroyView()中釋放資源,例如ButterKnife在onCreateView()時通過Unbinder對象unbinder=ButterKnife.bind(this,view)綁定,在onDestoryView()中進行unbinder.unbind()解綁。
3.Layout
靜態調用
Fragment可以通過<fragment>標籤直接嵌入進Activity的XML佈局中,並聲明要調用哪個Fragment類,這裏'class'屬性也可以使用'android:name'替換。
MainActivity類及其佈局:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment"
class="com.joseph.fragmenttest.MainFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
MainFragment類及其佈局:
public class MainFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main,container,false);
return view;
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is Fragment"/>
</RelativeLayout>
靜態調用Fragment效果:
ListFragment
下面源碼緊接着介紹了ListFragment的使用,但是它只貼出了部分代碼,想要跑起來這個demo要簡單改動一下。
源碼總共有四塊。
1、新建兩個Fragment(TitlesFragment、DetailsFragment)把上面兩大塊代碼貼進去。
2、新建個DetailsActivity類直接把第三塊源碼貼進去。
3、最後一塊是MainActivity的橫屏佈局。而豎屏佈局只用寫一個fragment,如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/titles"
android:name="你的包名.TitlesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
4、這時候還要建一個Shakespeare類作爲數據源,如下所示:
public class Shakespeare {
public static ArrayList<String> TITLES = new ArrayList<String>();
public static ArrayList<String> DIALOGUE = new ArrayList<String>();
static {
for (int i = 0; i < 50; i++) {
TITLES.add("這是第"+(i+1)+"的Item");
DIALOGUE.add("這是第"+(i+1)+"的Details");
}
}
}
然後有些小問題的地方稍微改改就能跑起來了。大致的效果就是豎屏時,只顯示一個TitlesFragment列表,點擊會跳轉到DetailsActivity顯示具體的信息,橫屏時DetailsActivity會自己finish掉,回到MainActivity並調用橫屏佈局,左邊TitlesFragment,右邊是DetailsFragment。
這裏有一點小優化就是把TitlesFragment代碼裏的
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
提出到括號前面,否則當你第一次豎屏點擊一個item後橫過來,高亮顯示的是對應的item,但是當你繼續豎屏點擊其他item後再橫屏,高亮顯示的還是第一次點擊的item。奈何個人水平有限,研究了半天不知道具體原因,個人懷疑是和adapter中調用的simple_list_item_activated_1中textview的background有關。感興趣的可以研究研究,這裏點到爲止。