前言
- 本篇介紹 Fragment 的生命周期、常用 API 、簡(jiǎn)單使用、回退棧
- 參考博客:http://blog.csdn.net/lmj623565791/article/details/37970961
- 參考博客:http://blog.csdn.net/lmj623565791/article/details/37992017
正文
一、Fragment 的由來(lái)
Fragment 是在 Android 3.0 之后引入的,主要是為了解決手機(jī)和屏幕的適配問題,同時(shí),也能相應(yīng)解決 activity 中代碼量過大的問題,不過,從 Fragment 問世以來(lái),相關(guān)的爭(zhēng)論就不斷,有同意使用的,也有反對(duì)使用的,反對(duì)的大部分原因就是坑太多,不好用,但是就我來(lái)看,用的人還是很多,而且本人也在經(jīng)常使用,所以就來(lái)篇 Fragment 的大總結(jié)。
二、Fragment 的生命周期
Fragment 是嵌套在 Activity 中使用的,生命周期也與 Activity 極其相似,除了與 Activity 相同的幾個(gè)生命周期方法之外,另加了幾個(gè)與 Activity 相交互的幾個(gè)方法,如下圖所示:

幾個(gè)額外的方法的介紹如下:
-
onAttach(Context context) :當(dāng) Fragment 與 Activity 發(fā)生關(guān)聯(lián)的時(shí)候調(diào)用,( Activity 傳遞到此方法內(nèi))
此方法內(nèi)部還是調(diào)用的 onAttach(Activity activity) 方法
-
onCreateView ( LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState )
創(chuàng)建 Fragment 視圖的時(shí)候調(diào)用,
-
onViewCreated(View view, @Nullable Bundle savedInstanceState)
在 Activity 的 onCreate() 方法已返回時(shí)調(diào)用。
-
onDestroyView()
與 onCreateView 對(duì)應(yīng),當(dāng)該 Fragment 的視圖被移除時(shí)調(diào)用
-
onDetach()
與 onAttach 相對(duì)應(yīng),當(dāng) Fragment 與 Activity 關(guān)聯(lián)被取消時(shí)調(diào)用
三、不同包下的 Fragment 的區(qū)別
Fragment 分兩個(gè)不同包下:
android.support.v4.app.Fragment;
android.app.Fragment;
區(qū)別如下:
- 兼容版本不同
v4 包下的是為了兼容之 1.6 系統(tǒng)。
另一個(gè)包下的是兼容 3.0 以上系統(tǒng)。不過這個(gè)現(xiàn)在沒啥用了,因?yàn)楝F(xiàn)在的手機(jī)基本都在 4.0 以上了
大家都知道 Fragment 是嵌套在 Activity 中使用的,對(duì) Activity 的要求不同
v4 包下的就要求這個(gè) Activity 必須繼承自FragmentActivity
另一個(gè)包下的不要求,其中 FragmentActivity 集成自 Activity-
獲取 FragmentManager 的方式不同
v4 包下的是通過:getSupportFragmentManager();
另一個(gè)包下的是:getFragmentManager();
注意:
關(guān)于 Fragment 的一切都要配套使用,注意導(dǎo)包問題否則容易出現(xiàn)類似這種錯(cuò)誤: wrong 2nd argument type found 'android.app.Fragment.' required 'Android.support.v4.app.Fragment'
四、Fragment 常用 API
-
FragmentManager
這是 Fragment 管理者,要想操作 Fragment 必須先獲取管理者,根據(jù)不同的包,有兩種獲取方式:getFragmentManager() // v4 中,getSupportFragmentManager
-
FragmentTransaction
所有的操作都是基于此類的,調(diào)用此類的一系列方法來(lái)管理 Fragment ,
獲取方式:fragmentManager.beginTransaction();方法大致如下:
-
add()
往Activity中添加一個(gè)Fragment
-
remove()
從 Activity 中移除一個(gè) Fragment,如果被移除的 Fragment 沒有添加到回退棧這個(gè) Fragment 實(shí)例將會(huì)被銷毀。
-
replace()
使用另一個(gè) Fragment 替換當(dāng)前的,實(shí)際上就是 remove() 和 add() 的合體
-
hide()
隱藏當(dāng)前的 Fragment,僅僅是設(shè)為不可見,并不會(huì)銷毀
-
show()
顯示之前隱藏的 Fragment
-
detach()
會(huì)將 view 從 UI 中移除,和 remove() 不同,此時(shí) fragment 的狀態(tài)依然由 FragmentManager 維護(hù)。
-
attach()
重建 view 視圖,附加到 UI 上并顯示。
-
commit()
提交一個(gè)事務(wù),此方法必須要在 Activity 的 onSaveInstanceState 方法之前調(diào)用
五、使用 Fragment 的最簡(jiǎn)單的操作
1. 兩個(gè) Fragment
public class FirstFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.firstfragment_layout, container, false);
return inflate;
}
public class SecondFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.secondfragment_layout, container, false);
return inflate;
}
2. Activity 中
public class MainActivity extends AppCompatActivity {
@BindView(R.id.btn)
Button btn;
@BindView(R.id.fragment)
FrameLayout fragment;
private FragmentManager fragmentManager;
private FirstFragment firstFragment;
private FragmentTransaction fragmentTransaction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setDefaultFragment();
}
/**
* 設(shè)置默認(rèn)的 fragment
*/
private void setDefaultFragment() {
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
firstFragment = new FirstFragment();
fragmentTransaction.add(R.id.fragment, firstFragment, "first").commit();
}
@OnClick(R.id.btn)
public void onViewClicked() {
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction1 = supportFragmentManager.beginTransaction();
SecondFragment secondFragment = new SecondFragment();
fragmentTransaction1.replace(R.id.fragment, secondFragment, "second");
fragmentTransaction1.commit();
}
}
3. activity 中的 xml 文件如下:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.administrator.fragment_text.MainActivity">
<FrameLayout
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
</FrameLayout>
</LinearLayout>
點(diǎn)擊按鈕之后就能切換 Fragment
六、 Fragment 回退棧 ( 包含 Fragment 常用 API 調(diào)用生命周期方法詳解 )
個(gè)人對(duì)回退棧的理解為: 當(dāng) Fragment 入棧之后,能夠保存此 Fragment 的狀態(tài),通過返回鍵再次回到此 Fragment 的時(shí)候,數(shù)據(jù)依然存在!
回退棧就像 Activity 一樣,先進(jìn)后出,一層一層的
由于是真機(jī)測(cè)試,所以沒法提供動(dòng)圖
測(cè)試邏輯大概是這樣的:三個(gè) Fragment 按順序跳轉(zhuǎn),每個(gè) Fragment 中都有一個(gè)輸入框,測(cè)試是否能保存輸入框中的內(nèi)容,及調(diào)用的生命周期方法。
1. 三個(gè) Fragment 分別為:
- FirstFragment
package com.example.administrator.fragment_text.huituizhan;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* Created by Administrator on 2017/4/10.
*/
public class FirstFragment extends Fragment {
@BindView(R.id.editText)
EditText editText;
@BindView(R.id.btn)
Button btn;
Unbinder unbinder;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("FirstFragment","onCreateView");
View inflate = inflater.inflate(R.layout.huituizhan_first_fragment, container, false);
unbinder = ButterKnife.bind(this, inflate);
return inflate;
}
@Override
public void onAttach(Context context) {
Log.i("FirstFragment","onAttach");
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Log.i("FirstFragment","onCreate");
super.onCreate(savedInstanceState);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
Log.i("FirstFragment","onViewCreated");
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onStart() {
Log.i("FirstFragment","onStart");
super.onStart();
}
@Override
public void onResume() {
Log.i("FirstFragment","onResume");
super.onResume();
}
@Override
public void onPause() {
Log.i("FirstFragment","onPause");
super.onPause();
}
@Override
public void onStop() {
Log.i("FirstFragment","onStop");
super.onStop();
}
@Override
public void onDestroyView() {
Log.i("FirstFragment","onDestroyView");
super.onDestroyView();
unbinder.unbind();
}
@Override
public void onDestroy() {
Log.i("FirstFragment","onDestroy");
super.onDestroy();
}
@Override
public void onDetach() {
Log.i("FirstFragment","onDetach");
super.onDetach();
}
/**
* 點(diǎn)擊按鈕切換到 SecondFragment
*/
@OnClick(R.id.btn)
public void onViewClicked() {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
SecondFragment secondFragment = new SecondFragment();
fragmentTransaction.hide(this);
fragmentTransaction.add(R.id.framelayout,secondFragment,"second");
// 將 FirstFragment 添加至 回退棧
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
注意此處切換 Fragment 使用的是:
fragmentTransaction.hide(this);
fragmentTransaction.add(R.id.framelayout,secondFragment,"second");
- SecondFragment
package com.example.administrator.fragment_text.huituizhan;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* Created by Administrator on 2017/4/10.
*/
public class SecondFragment extends Fragment {
@BindView(R.id.editText)
EditText editText;
@BindView(R.id.btn)
Button btn;
Unbinder unbinder;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.huituizhan_second_fragment, container, false);
unbinder = ButterKnife.bind(this, inflate);
Log.i("SecondFragment","onCreateView");
return inflate;
}
@Override
public void onAttach(Context context) {
Log.i("SecondFragment","onAttach");
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Log.i("SecondFragment","onCreate");
super.onCreate(savedInstanceState);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
Log.i("SecondFragment","onViewCreated");
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onStart() {
Log.i("SecondFragment","onStart");
super.onStart();
}
@Override
public void onResume() {
Log.i("SecondFragment","onResume");
super.onResume();
}
@Override
public void onPause() {
Log.i("SecondFragment","onPause");
super.onPause();
}
@Override
public void onStop() {
Log.i("SecondFragment","onStop");
super.onStop();
}
@Override
public void onDestroyView() {
Log.i("SecondFragment","onDestroyView");
super.onDestroyView();
unbinder.unbind();
}
@Override
public void onDestroy() {
Log.i("SecondFragment","onDestroy");
super.onDestroy();
}
@Override
public void onDetach() {
Log.i("SecondFragment","onDetach");
super.onDetach();
}
@OnClick(R.id.btn)
public void onViewClicked() {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ThreeFragment threeFragment = new ThreeFragment();
fragmentTransaction.replace(R.id.framelayout,threeFragment,"three");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
注意此處切換 Fragment 使用的是:
fragmentTransaction.replace(R.id.framelayout,threeFragment,"three");
- ThreeFragment
package com.example.administrator.fragment_text.huituizhan;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* Created by Administrator on 2017/4/10.
*/
public class ThreeFragment extends Fragment {
@BindView(R.id.editText)
EditText editText;
@BindView(R.id.btn)
Button btn;
Unbinder unbinder;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.huituizhan_three_fragment, container, false);
unbinder = ButterKnife.bind(this, inflate);
return inflate;
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@OnClick({R.id.editText, R.id.btn})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.editText:
break;
case R.id.btn:
Toast.makeText(getActivity().getApplicationContext(),"最后一個(gè)了",Toast.LENGTH_SHORT)
.show();
break;
}
}
}
2. Activity 中的代碼為:
package com.example.administrator.fragment_text.huituizhan;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.widget.FrameLayout;
import com.example.administrator.fragment_text.R;
import butterknife.BindView;
import butterknife.ButterKnife;
public class HuiTuiZhanActivity extends AppCompatActivity {
@BindView(R.id.framelayout)
FrameLayout framelayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hui_tui_zhan);
ButterKnife.bind(this);
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
FirstFragment firstFragment = new FirstFragment();
fragmentTransaction.add(R.id.framelayout,firstFragment,"first").commit();
}
}
3. 運(yùn)行之后,hide、add 與 replace 都能保存數(shù)據(jù),但是生命周期不太一樣,如下所示:
- FirstFragment 跳轉(zhuǎn)到 SecondFragment 時(shí):
04-22 13:43:10.160 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onAttach
04-22 13:43:10.160 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onCreate
04-22 13:43:10.160 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onCreateView
04-22 13:43:10.180 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onViewCreated
04-22 13:43:10.180 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStart
04-22 13:43:10.180 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onResume
04-22 13:43:26.605 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onAttach
04-22 13:43:26.605 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onCreate
04-22 13:43:26.615 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onCreateView
04-22 13:43:26.620 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onViewCreated
04-22 13:43:26.620 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStart
04-22 13:43:26.620 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onResume
注意: 此處切換的時(shí)候,沒有立馬調(diào)用 FirstFragment 的 onPause、onStop、onDestroyView
- SecondFragment 跳轉(zhuǎn)到 ThreeFragment 時(shí):
04-22 13:45:22.035 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onPause
04-22 13:45:22.035 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStop
04-22 13:45:22.035 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDestroyView
04-22 13:45:22.040 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onPause
04-22 13:45:22.040 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStop
04-22 13:45:22.040 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDestroyView
注意:此處是先調(diào)用 SecondFragment 的 onPause、onStop、onDestroyView,然后才調(diào)用 FirstFragment 的對(duì)應(yīng)方法,
- 按返回鍵 ThreeFragment 回退到 SecondFragment 時(shí):
04-22 13:51:26.075 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onCreateView
04-22 13:51:26.085 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onViewCreated
04-22 13:51:26.090 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStart
04-22 13:51:26.090 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onResume
04-22 13:51:26.095 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onCreateView
04-22 13:51:26.100 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onViewCreated
04-22 13:51:26.100 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStart
04-22 13:51:26.100 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onResume
注意: 此處竟然先調(diào)用的是 FirstFragment 的 onCreateView、onViewCreated、onStart、onResume
- 繼續(xù)按返回鍵 SecondFragment 回退到 FirstFragment 時(shí):
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onPause
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onStop
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDestroyView
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDestroy
04-22 13:52:30.825 15361-15361/com.example.administrator.fragment_text I/SecondFragment: onDetach
- 繼續(xù)返回鍵 退出 Activity 時(shí):
04-22 13:53:33.675 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onPause
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onStop
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDestroyView
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDestroy
04-22 13:53:34.045 15361-15361/com.example.administrator.fragment_text I/FirstFragment: onDetach
4. Fragment 退棧方式
這有個(gè)哥們寫的非常詳細(xì):http://blog.csdn.net/u010049692/article/details/38944867