Android Fragment 从源码的角度去解析(上)
###1.概述
本來想著昨天星期五可以早點休息,今天可以早點起來跑步,可沒想到事情那么的多,晚上有人問我主頁怎么做到點擊才去加載Fragment數(shù)據(jù),而不是一進入主頁就去加載所有的數(shù)據(jù),在這里自己就對Fragment做一個解析,這個應該可以算是很基礎的東西了。 上個月的訪問量已經(jīng)超過了10萬,堅持寫這個還是很有激情的,等到總數(shù)超過100萬的時候,會利用空閑的時間去錄制一整套Android的視頻,希望可以跟后來者一同學習。 我們還是老套路先看google官方理論以及源碼,然后將其整合到項目中,看一下項目效果。附視頻地址:http://pan.baidu.com/s/1mhUus56
###2.官方解析
2.1 Fragment簡介:
google官方簡介,官方現(xiàn)在打開都會自動翻譯,突然有點不適應一定需要翻墻,我這里就直接去copy重要部分: Fragment 表示 Activity 中的行為或用戶界面部分。您可以將多個片段組合在一個 Activity 中來構建多窗格 UI,以及在多個 Activity 中重復使用某個片段。您可以將片段視為 Activity 的模塊化組成部分,它具有自己的生命周期,能接收自己的輸入事件,并且您可以在 Activity 運行時添加或移除片段(有點像您可以在不同 Activity 中重復使用的“子 Activity”)。
片段必須始終嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影響。 例如,當 Activity 暫停時,其中的所有片段也會暫停;當 Activity 被銷毀時,所有片段也會被銷毀。 不過,當 Activity 正在運行(處于已恢復生命周期狀態(tài))時,您可以獨立操縱每個片段,如添加或移除它們。 當您執(zhí)行此類片段事務時,您也可以將其添加到由 Activity 管理的返回棧 — Activity 中的每個返回棧條目都是一條已發(fā)生片段事務的記錄。 返回棧讓用戶可以通過按返回按鈕撤消片段事務(后退)。
當您將片段作為 Activity 布局的一部分添加時,它存在于 Activity 視圖層次結構的某個 ViewGroup 內(nèi)部,并且片段會定義其自己的視圖布局。您可以通過在 Activity 的布局文件中聲明片段,將其作為 元素插入您的 Activity 布局中,或者通過將其添加到某個現(xiàn)有 ViewGroup,利用應用代碼進行插入。不過,片段并非必須成為 Activity 布局的一部分;您還可以將沒有自己 UI 的片段用作 Activity 的不可見工作線程。
2.2 Fragment和Activity生命周期關聯(lián):
Fragment有自己的生命周期比Activity的生命周期相對來說復雜一些,但是Fragment必須依附Activity所以兩者的生命周期是有關聯(lián)的
這里可以先看看不做過多的說明看源碼的時候會做重點分析的。2.3 Fragment相關API使用: 新建一個類extends Fragment這個時候會有兩個包可以導,我們肯定導v4包的其實都一樣,只不過v4的可以兼容Android 3.0(API 級別 11)以下的,一定要需要復寫他的onCreateView()方法,該方法返回值是一個View,代表當前碎片F(xiàn)ragment長什么樣子,到這里我們可以自己思考如果要我去實現(xiàn)寫一個Fragment會用什么樣的邏輯,因為待會我們要分析源碼的。
public static class ExampleFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.example_fragment, container, false);} } 復制代碼我們的使用方式有兩種一種是直接在布局文件中使用,這種并不是很常見,不做過多的說明,像使用View一樣但需要小寫fragment和指定name是Fragment的全類名,具體代碼如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><fragment android:name="com.example.news.ExampleFragment"android:id="@+id/list"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent" /> </LinearLayout> 復制代碼還有一種是重頭戲,比較常見我們以上面演示的項目效果為例,下面是RadioGroup中間是四個Fragment,必須依附ViewGroup那么整個布局就是:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/root_view"android:layout_width="match_parent"android:layout_height="match_parent"android:clipToPadding="false"android:fitsSystemWindows="true"android:orientation="vertical"><FrameLayoutandroid:id="@+id/main_tab_fl"android:layout_width="wrap_content"android:layout_height="0dp"android:layout_weight="1" /><RadioGroupandroid:background="@color/title_bar_bg_day"android:id="@android:id/tabs"android:layout_width="fill_parent"android:layout_height="@dimen/tab_height"android:layout_alignParentBottom="true"android:gravity="bottom"android:orientation="horizontal"><RadioButtonandroid:id="@+id/home_rb"style="@style/home_bottom_tab_style"android:drawableTop="@drawable/ic_tab_home"android:text="首頁" /><RadioButtonandroid:id="@+id/find_rb"style="@style/home_bottom_tab_style"android:drawableTop="@drawable/ic_tab_discovery"android:text="發(fā)現(xiàn)" /><RadioButtonandroid:id="@+id/new_rb"style="@style/home_bottom_tab_style"android:drawableTop="@drawable/ic_tab_fresh"android:text="新鮮" /><RadioButtonandroid:id="@+id/message_rb"style="@style/home_bottom_tab_style"android:drawableTop="@drawable/ic_tab_msg"android:text="消息" /></RadioGroup> </LinearLayout>復制代碼中間是FrameLayout,我們看官方的文檔就知道只要是ViewGroup就行,當我們不斷的點擊下面的Tab按鈕我們就有代碼去動態(tài)的替換Fragment,這里需要介紹兩個API ,官方這么說的: 您可以在 Activity 運行期間隨時將片段添加到 Activity 布局中。您只需指定要將片段放入哪個 ViewGroup。 要想在您的 Activity 中執(zhí)行片段事務(如添加、移除或替換片段),您必須使用 FragmentTransaction 中的 API。您可以像下面這樣從 Activity 獲取一個 FragmentTransaction 實例:
FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 復制代碼然后,您可以使用 add() 方法添加一個片段,指定要添加的片段以及將其插入哪個視圖。例如:
HomeFragment fragment = new HomeFragment();fragmentTransaction.add(R.id.main_tab_fl, fragment);fragmentTransaction.commit(); 復制代碼傳遞到 add() 的第一個參數(shù)是 ViewGroup,即應該放置片段的位置,由資源 ID 指定,第二個參數(shù)是要添加的片段。 一旦您通過 FragmentTransaction 做出了更改,就必須調(diào)用 commit() 以使更改生效。添加沒有 UI 的片段。如果需要做到切換就需要使用這個replace(int id, Fragment fragment)。 ###3.效果初步實現(xiàn)
新建四個Fragment,里面的內(nèi)容基本一致:
public class FindFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View rootView = inflater.inflate(R.layout.fragment_layout, null);TextView contentTv = (TextView) rootView.findViewById(R.id.content_tv);contentTv.setText("發(fā)現(xiàn)");return rootView;} } 復制代碼在主MainActivity中使用上面講到的兩個方法:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {private HomeFragment mHomeFragment;private FindFragment mFindFragment;private NewFragment mNewFragment;private MessageFragment mMessageFragment;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.home_rb).setOnClickListener(this);findViewById(R.id.find_rb).setOnClickListener(this);findViewById(R.id.new_rb).setOnClickListener(this);findViewById(R.id.message_rb).setOnClickListener(this);// 默認一進入頁面就添加主FragmentFragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();mHomeFragment = new HomeFragment();fragmentTransaction.add(R.id.main_tab_fl, mHomeFragment);// 最后記得提交fragmentTransaction.commit();}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.home_rb:homeRbClick();break;case R.id.find_rb:findRbClick();break;case R.id.new_rb:newRbClick();break;case R.id.message_rb:messageRbClick();break;}}private void homeRbClick() {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();// 替換成當前頁面fragmentTransaction.replace(R.id.main_tab_fl, mHomeFragment);fragmentTransaction.commit();}private void findRbClick() {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();if (mFindFragment == null) {mFindFragment = new FindFragment();}fragmentTransaction.replace(R.id.main_tab_fl, mFindFragment);fragmentTransaction.commit();}private void newRbClick() {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();if (mNewFragment == null) {mNewFragment = new NewFragment();}fragmentTransaction.replace(R.id.main_tab_fl, mNewFragment);fragmentTransaction.commit();}private void messageRbClick() {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();if (mMessageFragment == null) {mMessageFragment = new MessageFragment();}fragmentTransaction.replace(R.id.main_tab_fl, mMessageFragment);fragmentTransaction.commit();} }復制代碼目前的效果是這個樣子的,看似沒有任何的問題,這個也是最簡單的方式,下面我們就去整合到項目中,再去分析源碼以及Fragment的加載流程具體請看這里:Android Fragment 從源碼的角度去解析(下)
總結
以上是生活随笔為你收集整理的Android Fragment 从源码的角度去解析(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mac M1 搭建虚拟机节点集群过程及软
- 下一篇: Python有哪些优势?