前言
- 本篇介紹 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ī)和屏幕的適配問(wèn)題,同時(shí)狮惜,也能相應(yīng)解決 activity 中代碼量過(guò)大的問(wèn)題高诺,不過(guò),從 Fragment 問(wèn)世以來(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)豹悬。不過(guò)這個(gè)現(xiàn)在沒(méi)啥用了葵陵,因?yàn)楝F(xiàn)在的手機(jī)基本都在 4.0 以上了
大家都知道 Fragment 是嵌套在 Activity 中使用的,對(duì) Activity 的要求不同
v4 包下的就要求這個(gè) Activity 必須繼承自FragmentActivity
另一個(gè)包下的不要求瞻佛,其中 FragmentActivity 集成自 Activity-
獲取 FragmentManager 的方式不同
v4 包下的是通過(guò):getSupportFragmentManager();
另一個(gè)包下的是:getFragmentManager();
注意:
關(guān)于 Fragment 的一切都要配套使用脱篙,注意導(dǎo)包問(wèn)題否則容易出現(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 沒(méi)有添加到回退棧這個(gè) Fragment 實(shí)例將會(huì)被銷毀。
-
replace()
使用另一個(gè) Fragment 替換當(dāng)前的然遏,實(shí)際上就是 remove() 和 add() 的合體
-
hide()
隱藏當(dāng)前的 Fragment贫途,僅僅是設(shè)為不可見(jiàn),并不會(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)农猬,通過(guò)返回鍵再次回到此 Fragment 的時(shí)候,數(shù)據(jù)依然存在售淡!
回退棧就像 Activity 一樣斤葱,先進(jìn)后出,一層一層的
由于是真機(jī)測(cè)試揖闸,所以沒(méi)法提供動(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í)候隙畜,沒(méi)有立馬調(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