Android app包下fragment詳細使用

去年年底的時候需要改一個項目,接觸到了fragment。也沒有對fragment進行系統的學習,就開始動手改了,邊改邊學,現在閒下來了,對fragment進行一些總結。

  • 什麼是Fragment?
  • Fragment與Activity的區別
  • Fragment的生命週期
  • Fragment的簡單使用
  • Fragment的回退棧
  • Fragment的通信

1.什麼是fragment?
Fragment是Android3.0提出來的,之前剛提出來的時候,是不兼容Android3.0以下的版本(話說現在已經沒有人使用3.0以下的手機了吧),爲了兼容低版本,就出現了v4包下的fragment,網絡上對fragment的使用一般都是v4包下fragment,對於app包下的fragment的使用不僅很少,而且都是教程不全,或者坑太多。此文對app包下的fragment做一個詳細的講解。對於fragment,我們可以簡單的理解爲,是在Activity中的Activity。它可以顯示在Activity中,顯示出自己的內容。但是fragment是依賴於Activity存在的,不能夠自己單獨存在,同樣的一個Activity中可以有多個fragment,而且一個fragment可以被多個Activity使用,擁有自己的生命週期,我們可以在Activity中動態的進行fragment的添加刪除。說到這裏,感覺有點像Android中include的使用了,但是include只是相當於告訴編譯器,這裏只是放入了一個佈局,去加載這個佈局,但是fragment是讓編譯器去實例化這個fragment。
2. Fragment與Activity的區別?
fragment與Activity都擁有自己的生命週期。
Activity的生命週期:

onCreate()-onStart()-onResume()-onPause()-onStop()-onDestroy()-onRestart()
fragment的生命週期:

onAttach()-onCreate()-onCreateView()-onActivityCreated()-onStart()-onResume()-onPause()- onStop()-onDestroyView()-onDestroy()-onDetach()

通過生命週期可以明顯的看出來fragment比activity的生命週期要多,同時一個activity就是一個activity,fragment的意思就是碎片,所謂碎片,就反應出來了fragment比activity靈活,好控制。

fragment的使用優勢有以下幾點:

  • 模塊化:我們不需要把所有代碼全部都寫在Activity中,而是把代碼寫在各自的fragmen中,減少了代碼的複雜性,後期維護比較簡單。
  • 可重性:多個Activity可以重用同一個fragment。
  • 適配性:根據不同手機的尺寸,方向,可以實現不同的佈局,使客戶的體驗性更好。

3.Fragment的生命週期
生命週期前面我門已經看到了,這裏具體講一下各生命週期的區別:
先給張圖:
在這裏插入圖片描述
對於activity的生命週期想必大家都已經很熟悉了,這裏只介紹fragment的生命週期:
onAttach(Activity) 當Fragment與Activity發生關聯的時候調用,可以通過getArguments()獲取參數
onCreate():Fragment被創建時調用
onCreateView(LayoutInflater, ViewGroup, Bundle) 創建fragment佈局
onActivityCreated(Bundle) 加載佈局結束後調用
onStart():當Fragment可見調用。
onResume():當Fragment可見且可交互時調用。
onPause():當Fragment不可交互但可見時調用。
onStop():當Fragment不可見時調用。
onDestroyView() Fragment的佈局被移除時調用
onDestroy():銷燬Fragment時調用。
onDetach() Fragment和Activity解除關聯的時候調用
4.Fragment的簡單使用
fragment有兩種使用方法,一種是靜態使用,一種是動態使用。
靜態使用:
靜態使用就是在佈局的xml文件中添加name屬性去加載fragment,這種方式有一個缺點,就是在fragment運行的時候,不能夠進行刪除這個fragment,因此我們一般用動態加載就可以了。
(1):創建佈局文件fragment_home.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<Button
    android:id="@+id/btn_one"
    android:text="1111"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
</Button>
    <Button
        android:id="@+id/btn_two"
        android:text="2222"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>
    <Button
        android:id="@+id/btn_three"
        android:text="3333"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>
    <Button
        android:id="@+id/btn_four"
        android:text="4444"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>
</LinearLayout>

(2):創建一個類BaseFragment繼承Fragment,重寫onAttach方法:

public class BaseFragment extends Fragment {
    public String TAG = getClass().getSimpleName();
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
    }
}

(3):創建一個HomeFragment類,重寫onCreateView方法。進行fragment的具體操作,繼承上面創建的類BaseFragment(你們也可以直接創建HomeFragment類,重寫onAttach方法):

public class HomeFragment extends BaseFragment {
    public  HomeFragment(){
    /*對於爲什麼要使用無參構造函數,是因爲當屏幕方向發生變化的時候,
    會重新構造fragment,會優先調用fragment無參的構造方法,
    如果參數是通過構造函數傳遞的,在重新構造fragment時,參數就會丟失。
    如果要在fragment創建的時候就要傳入參數,不建議使用構造函數,
    可以使用setArguments()方式進行添加,因爲如果fragment被系統殺掉再次恢復的時候,
    能夠保留這些數據,後面將會介紹這種方法*/
    }

    /**
     * 加載佈局時候調用
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 1. 加載佈局,第三個參數必須爲`false`,否則會加載兩次佈局並且拋出異常!!
        //原因:在fragment內部中,會將佈局添加到container中,如果設置爲true,就會重複兩個添加,報IllegalStateException異常
        return inflater.inflate(R.layout.fragment_home,container,false);
    }
}

(3):Acticity對應的佈局文件(注意name標籤,就是指定Activity加載哪一個fragment):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:name="com.example.dhd.fragmentdemo.fragment.HomeFragment"
        android:id="@+id/fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </fragment>
</RelativeLayout>

(4):MainActivity對應代碼(網上很多人說使用app包下的fragment繼承Activity即可,我試了繼承Activity程序會直接崩潰,繼承AppCompatActivity或者FragmentActivity纔可以成功運行(AppCompatActivity是FragmentActivity的一個子類)。):

public class MainActivity extends AppCompatActivity {

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

運行效果:
在這裏插入圖片描述
動態使用:
對於動態加載的使用,我在使用的時候因爲不仔細,讓我自己煩惱了很長時間。
靜態加載的佈局文件中使用的標籤是fragment,而在動態加載中使用的標籤是FrameLayout。主要動態加載佈局文件不要使用fragment,否則你會和我一樣很苦惱爲什麼報錯而且找不到問題所在。
先看一下效果:
在這裏插入圖片描述
剛開始顯示的是fragment_home.xml,點擊跳轉後,顯示的是fragment_one.xml

(1):activity_main佈局文件:
注意是FrameLayout標籤

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/btn_jump"
        android:text="跳轉"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>
        <FrameLayout
            android:layout_below="@+id/btn_jump"
            android:id="@+id/fragment"
            android:layout_width="match_parent"
            android:layout_height="200dp">
        </FrameLayout>
</RelativeLayout>

(2):創建兩個fragment佈局文件:
fragment_home.xml佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/btn_home"
        android:text="home"
        android:layout_width="match_parent"
        android:layout_height="40dp">
    </Button>
</RelativeLayout>

fragment_one.xml佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/btn_one"
        android:text="one"
        android:layout_width="match_parent"
        android:layout_height="40dp">
    </Button>
</RelativeLayout>

(3):創建對應佈局文件的fragmentActivity:

BaseFragment

public class BaseFragment extends Fragment {
    public String TAG = getClass().getSimpleName();
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
    }
}

HomeFragment

public class HomeFragment extends BaseFragment{

    public HomeFragment() {
    }
    /**
     * 加載佈局時候調用
     *
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 1. 加載佈局,第三個參數必須爲`false`,否則會加載兩次佈局並且拋出異常!!
        return inflater.inflate(R.layout.fragment_home, container, false);
    }
 }

OneFragment

public class OneFragment extends BaseFragment {
    public OneFragment() {
    }

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

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private HomeFragment homeFragment;
    private Button btn_jump;
    private FragmentManager fragmentManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        showFragment();
        btn_jump = (Button) findViewById(R.id.btn_jump);
        btn_jump.setOnClickListener(this);
    }
    private void showFragment() {
        //獲取FragmentManager管理對象,使用 getFragmentManager()方法已經過時,並且有錯誤。
         fragmentManager = getSupportFragmentManager();
        //獲取FragmentTransaction事物對象,並開啓事務
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        //創建fragment對象
        homeFragment = new HomeFragment();
        //操作fragment,佈局ID,fragment對象,還有第三個參數(tag,可寫可不寫)tag作爲fragment的唯一標誌,可以通過Fragment1 frag = getSupportFragmentManager().findFragmentByTag("tag")從FragmentManager中查找Fragment對象。
        fragmentTransaction.add(R.id.fragment, homeFragment);
        //提交事務
        fragmentTransaction.commit();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_jump:
                OneFragment oneFragment = new OneFragment();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                //replace就是替換fragment中原有的fragment,將其替換爲oneFragment,最後不要忘記commit,否則會沒有效果
                fragmentTransaction.replace(R.id.fragment,oneFragment).commit();
                break;
        }
    }
}

靜態加載和動態加載的使用就是這樣了,在項目中一般都是用動態加載的方法,畢竟靜態加載的時候是不能刪除正在使用的fragment。
補充一下fragmentTransaction的幾種使用方法:
fragmentTransaction.add() 向Activity中添加一個Fragment

  • transaction.remove()
    從Activity中移除一個Fragment,如果被移除的Fragment沒有添加到回退棧(回退棧後面會詳細說),這個Fragment實例將會被銷燬
  • fragmentTransaction.replace() 使用另一個Fragment替換當前的,實際上就是remove()然後add()的合體
  • fragmentTransaction.hide() 隱藏當前的Fragment,僅僅是設爲不可見,並不會銷燬
  • fragmentTransaction.show() 顯示之前隱藏的Fragment
  • detach() 會將view從UI中移除,和remove()不同,此時fragment的狀態依然由FragmentManager維護
  • attach() 重建view視圖,附加到UI上並顯示

fragmentTransaction.commit() 提交事務
注意:在add/replace/hide/show以後都要提交事務其效果纔會在屏幕上顯示出來
提交事務有四種方式:
1.commit():

  • 當你調用commit()的時候, FragmentManger會檢查是否已經存儲了它自己的狀態, 如果已經存在, 就拋出IllegalStateException,同樣說明每個事務只能存在一次,如果你再重新重新創建一個事務,再去提交,這個時候是沒有問題的。
  • 一旦調用這個方法, 這個commit()並不是立即執行的, 它會被髮送到主線程的任務隊列當中去, 當主線程準備好執行它的時候執行
  • Activity執行完onSaveInstanceState()方法後不能再執行commit()方法

2.commitAllowingStateLoss():

  • 當你調用commitAllowingStateLoss()的時候, FragmentManger不會檢查是否已經存儲了它自己的狀態, 也就不會拋出IllegalStateException.有效的解決了commit()提交時出現的問題。

3.commitNow():

  • 當你調用commitNow()時,將會立即執行並且只會執行你當前要提交的transaction。
  • 從v24.0.0開始提供了 commitNow()方法,在之前開發者會在commit()調用之後加上 executePendingTransactions()來保證立即執行, 即變異步爲同步,但是這樣會將所有pending在隊列中還有你新提交的transactions都執行了,而commitNow()就避免那些你可能並不想執行的transactions。

4.commitNowAllowingStateLoss():

  • 當你調用commitNowAllowingStateLoss()的時候, FragmentManger不會檢查是否已經存儲了它自己的狀態, 也就不會拋出IllegalStateException,並且會立即執行。

5.Fragment的回退棧
Fragment的回退棧是用來保存每一次Fragment事務發生的變化 如果你將Fragment任務添加到回退棧,當用戶點擊後退按鈕時,將看到上一次的保存的Fragment。一旦Fragment完全從後退棧中彈出,用戶再次點擊後退鍵,則退出當前Activity。官方的說法就是就是你在點擊後退鍵的時候,到底要不要顯示上一個fragment.
要把fragment添加到回退棧,需要學會一個方法:
FragmentTransaction.addToBackStack(String)
下面用案列進行演示:
先看一下效果圖:
我默認第一個Activity打開homeFragment,在輸入框內輸入111.點擊HOME,將HomeFragment覆蓋爲OneFragment,輸入222,點擊ONE,將OneFragment覆蓋爲TwoFragment,點擊返回鍵,返回到OneFragment,可以看到輸入框上面還有,再次點擊返回鍵,返回到HomeFragment,輸入框有222。這裏我們再次點擊到最後一個fragment,點擊two,跳轉到第二個Activity.
在這裏插入圖片描述
先來看一下文件目錄:
在這裏插入圖片描述
下面來看代碼:
fragment_home.xml佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/btn_home"
        android:text="home"
        android:layout_width="match_parent"
        android:layout_height="40dp">
    </Button>
    <EditText
        android:id="@+id/et_home"
        android:layout_below="@+id/btn_home"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </EditText>
</RelativeLayout>

activity_main.xml佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
        <FrameLayout
            android:id="@+id/fragment"
            android:layout_width="match_parent"
            android:layout_height="200dp">
        </FrameLayout>
</RelativeLayout>

fragment_one.xml佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
    android:id="@+id/btn_one"
    android:text="one"
    android:layout_width="match_parent"
    android:layout_height="40dp">
</Button>
    <EditText
        android:id="@+id/et_one"
        android:layout_below="@+id/btn_one"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </EditText>
</RelativeLayout>

fragment_two.xml佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/btn_two"
        android:text="two"
        android:layout_width="match_parent"
        android:layout_height="40dp">
    </Button>
    <EditText
        android:id="@+id/et_two"
        android:text="已經到最後一個fragment了"
        android:layout_below="@+id/btn_two"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </EditText>
</RelativeLayout>

activity_second.xml佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">
    <TextView
        android:text="第二個Activity"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </TextView>
</RelativeLayout>

MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private HomeFragment homeFragment;
    private FragmentManager fragmentManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        showFragment();
    }
    private void showFragment() {
        //獲取FragmentManager管理對象
         fragmentManager = getSupportFragmentManager();
        //獲取FragmentTransaction事物對象,並開啓事務
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        //創建fragment對象
        homeFragment = new HomeFragment();
        //操作fragment,佈局ID,fragment對象
        fragmentTransaction.add(R.id.fragment, homeFragment);
        //提交事務
        fragmentTransaction.commit();
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        }
    }
}

BaseFragment:

public class BaseFragment extends Fragment {
    public String TAG = getClass().getSimpleName();
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
    }
}

HomeFragment:

public class HomeFragment extends BaseFragment implements View.OnClickListener {
    private Button btn_home;
    public HomeFragment() {
    }
    /**
     * 加載佈局時候調用
     *
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 1. 加載佈局,第三個參數必須爲`false`,否則會加載兩次佈局並且拋出異常!!
         View v = inflater.inflate(R.layout.fragment_home, container, false);
         btn_home = v.findViewById(R.id.btn_home);
         btn_home.setOnClickListener(this);
        return v;
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_home:
                Log.e(TAG,"點擊了home");
                FragmentManager fragmentManager = getFragmentManager();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                OneFragment oneFragment = new OneFragment();
                fragmentTransaction.replace(R.id.fragment,oneFragment);
                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();
                break;
        }
    }

    /**
     * 加載佈局結束後調用
     *
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    /**
     * Fragment的佈局被移除時調用
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }

    /**
     * Fragment和Activity解除關聯的時候調用
     */
    @Override
    public void onDetach() {
        super.onDetach();
    }
}

OneFragment:

public class OneFragment extends BaseFragment implements View.OnClickListener {
    private Button btn_one;

    public OneFragment() {
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_one, container, false);
        btn_one = v.findViewById(R.id.btn_one);
        btn_one.setOnClickListener(this);
        return v;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_one:
                FragmentManager fragmentManager = getFragmentManager();
                TwoFragment twoFragment = new TwoFragment();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                fragmentTransaction.replace(R.id.fragment,twoFragment);
                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();
                break;
        }
    }
}

TwoFragment:

public class TwoFragment extends BaseFragment implements View.OnClickListener {
    private Button btn_two;
    public TwoFragment() {
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v =  inflater.inflate(R.layout.fragment_two, container, false);
        btn_two = v.findViewById(R.id.btn_two);
        btn_two.setOnClickListener(this);
        return v;
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_two:
            	//fragment跳轉到Activity與平常不同,注意一下
                startActivity(new Intent(getActivity(), SecondActivity.class));
                break;
        }
    }
}

SecondActivity:

public class SecondActivity extends AppCompatActivity {

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

6.Fragment的通信
fragment的通信有三種情況,這三種情況都可以用EventBus進行傳值。使用傳統的方式太麻煩。
EventBus的使用請參考我的另一邊博客
EventBus使用超鏈接
當我們使用EvensBus的時候,有時候收到消息的活動,可能還沒有加載,也就是沒有進行註冊EventBus,這個時候我們使用普通的發送消息是不行的,我們需要使用EventBus的粘性事件。
建議不會使用EventBus或者不會使用EventBus粘性事件的先去上面的鏈接學習一下。

  1. Fragment向Activity傳遞數據
  2. Activity向Fragment傳遞數據
  3. Fragment之間傳遞數據
    補充一下,本來Event的名字FA代表fragment向Activity傳遞數據,後來發現AF和FA弄反了,大家湊合看吧。
    將他們寫到了一起,先來看看效果。
    在這裏插入圖片描述
    首先剛啓動的時候我使用EventBus在Activity中發送了粘性事件,默認啓動HomeFragment,啓動的時候註冊EventBus,將1111傳遞到HomeFragment中(Activity向Fragment傳遞數據),在HomeFragment中我點擊home,發送粘性事件,將2222傳遞到OneFragment(Fragment之間傳遞數據)。當我點擊two的時候,將3333傳遞到SecondActivity(Fragment向Activity傳遞數據)。

下面來看代碼:
根據上面的回退棧的代碼做了一些修改,只發布修改的地方
目錄:
在這裏插入圖片描述
MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private HomeFragment homeFragment;
    private FragmentManager fragmentManager;

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

    private void initView() {
        showFragment();
    }

    private void showFragment() {
        //發佈粘性事件
        EventBus.getDefault().postSticky(new FAEvetn("1111"));
        //獲取FragmentManager管理對象
        fragmentManager = getSupportFragmentManager();
        //獲取FragmentTransaction事物對象,並開啓事務
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        //創建fragment對象
        homeFragment = new HomeFragment();
        //操作fragment,佈局ID,fragment對象
        fragmentTransaction.add(R.id.fragment, homeFragment);
        //提交事務
        fragmentTransaction.commit();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

HomeFragment:

public class HomeFragment extends BaseFragment implements View.OnClickListener {
    private Button btn_home;
    private EditText et_home;

    public HomeFragment() {
    }

    /**
     * 加載佈局時候調用
     *
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // 1. 加載佈局,第三個參數必須爲`false`,否則會加載兩次佈局並且拋出異常!!
        View v = inflater.inflate(R.layout.fragment_home, container, false);
        btn_home = v.findViewById(R.id.btn_home);
        et_home = v.findViewById(R.id.et_home);
        btn_home.setOnClickListener(this);
        if(!EventBus.getDefault().isRegistered(this)){
            EventBus.getDefault().register(this);
        }
        return v;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_home:
                //發佈粘性事件
                EventBus.getDefault().postSticky(new FFEvetn("2222"));
                FragmentManager fragmentManager = getFragmentManager();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                OneFragment oneFragment = new OneFragment();
                fragmentTransaction.replace(R.id.fragment,oneFragment);
                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();
                break;
        }
    }
    /**
     * 接收來自MainActivity的粘性事件
     * @param faEvetn
     */
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void faEvent(FAEvetn faEvetn) {
        et_home.setText(faEvetn.fa);
    }
    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
    /**
     * 加載佈局結束後調用
     *
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }
    /**
     * Fragment的佈局被移除時調用
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }
    /**
     * Fragment和Activity解除關聯的時候調用
     */
    @Override
    public void onDetach() {
        super.onDetach();
    }
}

OneFragment:

public class OneFragment extends BaseFragment implements View.OnClickListener {
    private Button btn_one;
    private EditText et_one;

    public OneFragment() {
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_one, container, false);
        btn_one = v.findViewById(R.id.btn_one);
        et_one = v.findViewById(R.id.et_one);
        btn_one.setOnClickListener(this);
        EventBus.getDefault().register(this);
        return v;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_one:
                FragmentManager fragmentManager = getFragmentManager();
                TwoFragment twoFragment = new TwoFragment();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                fragmentTransaction.replace(R.id.fragment, twoFragment);
                fragmentTransaction.addToBackStack(null);
                fragmentTransaction.commit();
                break;
        }
    }

    /**
     * 接收來自HomeFragment的粘性事件
     * @param ffEvetn
     */
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void faEvent(FFEvetn ffEvetn) {
        et_one.setText(ffEvetn.ff);
    }

    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
}

SecondActivity:

public class SecondActivity extends AppCompatActivity {

    private TextView tv_second_show;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        initView();
        EventBus.getDefault().register(this);
    }

    private void initView() {
        tv_second_show = (TextView) findViewById(R.id.tv_second_show);
    }
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void afEvent(AFEvrnt afEvrnt){
        tv_second_show.setText(afEvrnt.af);
    }
    @Override
    protected void onDestroy() {
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
}

activity_second.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">
    <TextView
        android:id="@+id/tv"
        android:text="第二個Activity"
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </TextView>
    <TextView
        android:layout_below="@+id/tv"
        android:id="@+id/tv_second_show"
        android:textColor="@color/colorAccent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </TextView>
</RelativeLayout>

FAEvent:

public class FAEvetn {
    public String fa;
    public FAEvetn(String fa) {
        this.fa = fa;
    }
}

FFEvent:

public class FFEvetn {
    public String ff;
    public FFEvetn(String ff) {
        this.ff = ff;
    }
}

AFEvrnt:

public class AFEvrnt {
    public String af;
    public AFEvrnt(String af) {
        this.af = af;
    }
}

fragment的使用暫時就先介紹到這裏有啥錯誤或者不對的地方歡迎提出。下面附上源代碼下載地址:
鏈接:https://pan.baidu.com/s/14OcE_ZZzNesi5tIevWw7Rw
提取碼:h4tz

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章