准备重新入手安卓了,依然选择从fragment开始。冲鸭~!
Fragment有如下两个选择
android.support.v4.app.Fragment
android.app.Fragment;
support.v4.app下的片段具有更好的兼容性,可以兼容到1.6版本,而app下的Fragment只支持3.0以上的版本,如果minsdk设置在3.0以上,当然用哪个都可以,如果需要兼容到3.0以下,建议使用V4包下的Fragment。
划重点1:support.v4.app下的片段可以兼容到1.6版本,且support.v4.app下的Fragment和app下的Fragment不具有继承关系,无法进行类型转换。
以support.v4.app下的Fragment为例,正式开始今天的学习。
首先使用replace的方式实现fragment的切换。
创建ShowFragment:
ShowFragment.java
public class ShowFragment extends Fragment {
private static final String TAG = "ShowFragment";
String mText;
public static ShowFragment getInstance(String text){
ShowFragment showFragment = new ShowFragment();
showFragment.mText = text;
return showFragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d(TAG, "onAttach: " + mText);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: " + mText);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: " + mText);
return inflater.inflate(R.layout.show_fragment,container,false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView text = view.findViewById(R.id.tv);
text.setText(mText);
Log.d(TAG, "onViewCreated: " + mText);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated: " + mText);
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart: " + mText);
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume: " + mText);
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause: " + mText);
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop: " + mText);
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView: " + mText);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: " + mText);
}
@Override
public void onDetach() {
super.onDetach();
Log.d(TAG, "onDetach: " + mText);
}
}
show_fragment.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">
<TextView
android:textSize="20sp"
android:textColor="#333333"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:id="@+id/tv"/>
</RelativeLayout>
然后创建承载Fragment的Activity:
FragmentShowActivity.java
public class FragmentShowActivity extends AppCompatActivity {
RelativeLayout mRoot;
ShowFragment show1;
ShowFragment show2;
Button btn;
FragmentManager fm;
boolean is1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_show);
mRoot = findViewById(R.id.rl);
btn = findViewById(R.id.btn);
show1 = ShowFragment.getInstance("show1");
show2 = ShowFragment.getInstance("show2");
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//*注意此处使用replace替换fragment
if (!is1) {
ft.replace(R.id.fragment, show1);
ft.commit();
} else {
ft.replace(R.id.fragment, show2);
ft.commit();
}
is1 = !is1;
}
});
}
}
activity_fregment_show.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"
android:id="@+id/rl"
tools:context=".FragmentShowActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="btn"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="50dp"
android:id="@+id/btn"/>
</RelativeLayout>
Activity中创建了命名为show1和show2的ShowFragment,以及一个控制Fragment替换的按钮,点击按钮会替换Fragment。
运行程序,第一次点击按钮输出如下(onViewCreated为onCreateView执行完成的回调方法,不属于Fragment生命周期)
执行顺序为
onAttach(初次绑定时调用)
onCreate(创建Fragment时调用)
onCreateView(创建Fragment布局时调用)
onActivityCreated(Activity的OnCreate调用完成后才会调用)
onStart(Fragment转变为可见状态)
onResume(Fragment转变为前台显示,可交互状态)
退回桌面执行
onPause(Fragment变为不可交互状态)
onStop(Fragment变为不可见状态)
再次进入程序
onStart
onResume
此时点击按钮替换为名叫show2的Fragment
替换操作执行多次,会发现都是先执行将要显示的Fragment的onAttach方法和onCreate方法,然后执行当前Fragment的销毁系列方法,最后才加载将显示的Fragment的布局并显示。
替换操作时前一个Fragment和后一个Fragment的生命周期有没有确定的时序关系还需要继续看源码才能确定,暂时不与讨论。
但可以确认的一点是 执行一次替换操作时,前一个Fragment会走一个完整的生命周期,即从绑定到解绑到操作。
切换Fragment除了使用replace,还可以使用hide和show。
将FragmentShowActivity的onCreate稍作修改,使用hide和show方法来做fragment的切换,看看现在fragment的生命周期会有何改变。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_show);
mRoot = findViewById(R.id.rl);
btn = findViewById(R.id.btn);
show1 = ShowFragment.getInstance("show1");
show2 = ShowFragment.getInstance("show2");
fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment, show1);
ft.add(R.id.fragment, show2);
ft.hide(show1);
ft.commit();
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (!is1) {
ft.hide(show1);
ft.show(show2);
ft.commit();
} else {
ft.hide(show2);
ft.show(show1);
ft.commit();
}
is1 = !is1;
}
});
}
启动app,查看日志
可以看到show1和show2的生命周期同步了,并且都在调用add方法时开始执行。
返回桌面再回app
果然很同步。。点击按钮切换一下看看回发生什么
没错。。什么都没有发生,fragment的生命周期不会因为show和hide而发生改变。
还有一种使用replace+回退栈的方式实现Fragment的切换,使用了回退栈后,Fragment的生命周期又不同了,这一现象将在下一篇文章进行分析,我们可以搬出那张经典的图,秘密藏在图里。