Fragment 的 声明周期、回退栈等
前言
- 本篇介绍 Fragment 的生命周期、常用 API 、简单使用、回退栈
- 参考博客:http://blog.csdn.net/lmj623565791/article/details/37970961
- 参考博客:http://blog.csdn.net/lmj623565791/article/details/37992017
正文
一、Fragment 的由来
Fragment 是在 Android 3.0 之后引入的,主要是为了解决手机和屏幕的适配问题,同时,也能相应解决 activity 中代码量过大的问题,不过,从 Fragment 问世以来,相关的争论就不断,有同意使用的,也有反对使用的,反对的大部分原因就是坑太多,不好用,但是就我来看,用的人还是很多,而且本人也在经常使用,所以就来篇 Fragment 的大总结。
二、Fragment 的生命周期
Fragment 是嵌套在 Activity 中使用的,生命周期也与 Activity 极其相似,除了与 Activity 相同的几个生命周期方法之外,另加了几个与 Activity 相交互的几个方法,如下图所示:
image几个额外的方法的介绍如下:
-
onAttach(Context context) :当 Fragment 与 Activity 发生关联的时候调用,( Activity 传递到此方法内)
此方法内部还是调用的 onAttach(Activity activity) 方法
-
onCreateView ( LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState )
创建 Fragment 视图的时候调用,
-
onViewCreated(View view, @Nullable Bundle savedInstanceState)
在 Activity 的 onCreate() 方法已返回时调用。
-
onDestroyView()
与 onCreateView 对应,当该 Fragment 的视图被移除时调用
-
onDetach()
与 onAttach 相对应,当 Fragment 与 Activity 关联被取消时调用
三、不同包下的 Fragment 的区别
Fragment 分两个不同包下:
android.support.v4.app.Fragment;
android.app.Fragment;
区别如下:
- 兼容版本不同
v4 包下的是为了兼容之 1.6 系统。
另一个包下的是兼容 3.0 以上系统。不过这个现在没啥用了,因为现在的手机基本都在 4.0 以上了
-
大家都知道 Fragment 是嵌套在 Activity 中使用的,对 Activity 的要求不同
v4 包下的就要求这个 Activity 必须继承自FragmentActivity
另一个包下的不要求,其中 FragmentActivity 集成自 Activity -
获取 FragmentManager 的方式不同
v4 包下的是通过:getSupportFragmentManager();
另一个包下的是:getFragmentManager();
注意:
关于 Fragment 的一切都要配套使用,注意导包问题否则容易出现类似这种错误: wrong 2nd argument type found 'android.app.Fragment.' required 'Android.support.v4.app.Fragment'
四、Fragment 常用 API
-
FragmentManager
这是 Fragment 管理者,要想操作 Fragment 必须先获取管理者,根据不同的包,有两种获取方式:getFragmentManager() // v4 中,getSupportFragmentManager
-
FragmentTransaction
所有的操作都是基于此类的,调用此类的一系列方法来管理 Fragment ,
获取方式:fragmentManager.beginTransaction();方法大致如下:
-
add()
往Activity中添加一个Fragment
-
remove()
从 Activity 中移除一个 Fragment,如果被移除的 Fragment 没有添加到回退栈这个 Fragment 实例将会被销毁。
-
replace()
使用另一个 Fragment 替换当前的,实际上就是 remove() 和 add() 的合体
-
hide()
隐藏当前的 Fragment,仅仅是设为不可见,并不会销毁
-
show()
显示之前隐藏的 Fragment
-
detach()
会将 view 从 UI 中移除,和 remove() 不同,此时 fragment 的状态依然由 FragmentManager 维护。
-
attach()
重建 view 视图,附加到 UI 上并显示。
-
commit()
提交一个事务,此方法必须要在 Activity 的 onSaveInstanceState 方法之前调用
五、使用 Fragment 的最简单的操作
1. 两个 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();
}
/**
* 设置默认的 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>
点击按钮之后就能切换 Fragment
六、 Fragment 回退栈 ( 包含 Fragment 常用 API 调用生命周期方法详解 )
-
个人对回退栈的理解为: 当 Fragment 入栈之后,能够保存此 Fragment 的状态,通过返回键再次回到此 Fragment 的时候,数据依然存在!
-
回退栈就像 Activity 一样,先进后出,一层一层的
-
由于是真机测试,所以没法提供动图
-
测试逻辑大概是这样的:三个 Fragment 按顺序跳转,每个 Fragment 中都有一个输入框,测试是否能保存输入框中的内容,及调用的生命周期方法。
1. 三个 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();
}
/**
* 点击按钮切换到 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(),"最后一个了",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. 运行之后,hide、add 与 replace 都能保存数据,但是生命周期不太一样,如下所示:
- FirstFragment 跳转到 SecondFragment 时:
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
注意: 此处切换的时候,没有立马调用 FirstFragment 的 onPause、onStop、onDestroyView
- SecondFragment 跳转到 ThreeFragment 时:
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
注意:此处是先调用 SecondFragment 的 onPause、onStop、onDestroyView,然后才调用 FirstFragment 的对应方法,
- 按返回键 ThreeFragment 回退到 SecondFragment 时:
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
注意: 此处竟然先调用的是 FirstFragment 的 onCreateView、onViewCreated、onStart、onResume
- 继续按返回键 SecondFragment 回退到 FirstFragment 时:
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
- 继续返回键 退出 Activity 时:
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 退栈方式
这有个哥们写的非常详细:http://blog.csdn.net/u010049692/article/details/38944867