FragmentManager的简单使用
本文查看一下使用fragmentmanager的hide(),show()方法后,fragment执行了什么生命周期
本文创建一个主活动,两个附属的fragment,代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private String tag = "debug";
public Fragment1 fragment1;
public Fragment2 fragment2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1=findViewById(R.id.button1);
Button button2=findViewById(R.id.button2);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
Log.d(tag, "oncreate");
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button1:
fragment1=new Fragment1();
getSupportFragmentManager().beginTransaction().add(R.id.container,fragment1).commit();
break;
case R.id.button2:
fragment2=new Fragment2();
getSupportFragmentManager().beginTransaction().hide(fragment1).commit();
getSupportFragmentManager().beginTransaction().add(R.id.container,fragment2).commit();
break;
}
}
@Override
protected void onStart () {
Log.d(tag, "onstart");
super.onStart();
}
@Override
protected void onStop () {
Log.d(tag, "onstop");
super.onStop();
}
@Override
protected void onDestroy () {
Log.d(tag, "ondestroy");
super.onDestroy();
}
@Override
protected void onPause () {
Log.d(tag, "onpause");
super.onPause();
}
@Override
protected void onResume () {
Log.d(tag, "onresume");
super.onResume();
}
}
package com.example.test.fragment;
import android.content.Context;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.example.test.MainActivity;
import com.example.test.R;
public class Fragment1 extends Fragment {
String tag="debug";
public TextView textView;
public void ran(){
;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(tag,"oncreateview1");
View view=inflater.inflate(R.layout.fragment1,container,false);
textView=view.findViewById(R.id.textView);
return view;
}
@Nullable
@Override
public void onAttach(@NonNull Context context) {
Log.d(tag,"onattachf1");
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Log.d(tag,"oncreatef1");
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Log.d(tag,"onacitvitycreated");
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
Log.d(tag,"onstartf1");
super.onStart();
}
@Override
public void onResume() {
Log.d(tag,"onresumef1");
super.onResume();
}
@Override
public void onPause() {
Log.d(tag,"onpausef1");
super.onPause();
}
@Override
public void onStop() {
Log.d(tag,"onstopf1");
super.onStop();
}
@Override
public void onDestroyView() {
Log.d(tag,"ondestroyviewf1");
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.d(tag,"ondestroyf1");
super.onDestroy();
}
@Override
public void onDetach() {
Log.d(tag,"ondetachf1");
super.onDetach();
}
}
package com.example.test.fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.example.test.MainActivity;
import com.example.test.R;
public class Fragment2 extends Fragment implements View.OnClickListener{
String tag="debug";
MainActivity mainActivity;
TextView text;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(tag,"oncreateview2");
View view=inflater.inflate(R.layout.fragment2,container,false);
mainActivity= (MainActivity) getActivity();
Button button=view.findViewById(R.id.button);
button.setOnClickListener(this);
text=view.findViewById(R.id.textView);
return view;
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button:
TextView textView=mainActivity.fragment1.textView;
text.setText(textView.getText().toString());
break;
}
}
@Nullable
@Override
public void onAttach(@NonNull Context context) {
Log.d(tag,"onattachf2");
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Log.d(tag,"oncreatef2");
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
Log.d(tag,"onacitvitycreatedf2");
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
Log.d(tag,"onstartf2");
super.onStart();
}
@Override
public void onResume() {
Log.d(tag,"onresumef2");
super.onResume();
}
@Override
public void onPause() {
Log.d(tag,"onpausef2");
super.onPause();
}
@Override
public void onStop() {
Log.d(tag,"onstopf2");
super.onStop();
}
@Override
public void onDestroyView() {
Log.d(tag,"ondestroyviewf2");
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.d(tag,"ondestroyf2");
super.onDestroy();
}
@Override
public void onDetach() {
Log.d(tag,"ondetachf2");
super.onDetach();
}
}
他们的布局文件并不需要展示,等下看运行截图就知道了。此处测试的核心代码是:
fragment2=new Fragment2();
getSupportFragmentManager().beginTransaction().hide(fragment1).commit();
getSupportFragmentManager().beginTransaction().add(R.id.container,fragment2).commit();
然后截图如下,这里的截图已经依次点击了按钮1和按钮2(事务请看MainAcitivity代码),并且点击了获取按钮3(点击按钮3其实就是为了查看这个fragment1的textview会不会因为hide而被销毁,所以此处在fragment2中测试下能不能获取那个textview中的内容,此处显示可以,fragment1的布局文件中textview的内容就是“fragment1中的数据”,也就是没有因为hide而销毁):
生命周期执行情况可以继续证明如下:
也即是说原来的fragment1还是在运行中的。
下面改变MainActivity中的onClick方法,如下(只改了一点点,表示把fragment1和2加入到返回栈):
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button1:
fragment1=new Fragment1();
getSupportFragmentManager().beginTransaction().add(R.id.container,fragment1).addToBackStack(null).commit();
break;
case R.id.button2:
fragment2=new Fragment2();
getSupportFragmentManager().beginTransaction().hide(fragment1).commit();
getSupportFragmentManager().beginTransaction().add(R.id.container,fragment2).addToBackStack(null).commit();
break;
}
}
再次运行,结果当然一样,这次操作只是额外manager把他们加入到返回栈而已。下面组另外测试,查看返回键对fragment的影响。按返回键,和平常你测试的时候只有一个MainAcitvity的时候按返回键会直接销毁是一样的。下面进行验证,按一次返回键后,也就是让fragment2出栈,生命周期执行情况为:
和预料的一样,但是此时fragment1布局中的内容却没有显示,为什么呢?按理此时栈顶是fragment1了啊,其实是我代码写错了,或者没有理解到fragmentmanager加入返回栈的含义,下面看下源码注释是怎么说的:
/**
* Add this transaction to the back stack. This means that the transaction
* will be remembered after it is committed, and will reverse its operation
* when later popped off the stack.
*
* {@link #setReorderingAllowed(boolean)} must be set totrue
* in the same transaction as addToBackStack() to allow the pop of that
* transaction to be reordered.
*
* @param name An optional name for this back stack state, or null.
*/
也就是说是把这次事务保存了一下,下次返回是返回到这次事务之前,而一次一次事务是按commit()来计算的,我前面代码那里,用了两个commit(),所以回到的是第二个之前的那个状态,也就是回到还没有加入fragment2之前的状态,所以你按返回键会销毁fragment2。但是这个状态在第一个commit()之后,此时fragment1已经隐藏了,所以就没有显示了。
下面修改代码,正确显示。
fragment2=new Fragment2();
getSupportFragmentManager().beginTransaction().hide(fragment1).commit();
getSupportFragmentManager().beginTransaction().add(R.id.container,fragment2).addToBackStack(null).commit();
break;
修改为
fragment2=new Fragment2();
getSupportFragmentManager().beginTransaction().hide(fragment1);
getSupportFragmentManager().beginTransaction().add(R.id.container,fragment2).addToBackStack(null).commit();
之后重新运行,在按返回键之前,发现显示fragment2的时候发生了重叠,fragment1难道没有隐藏?是的,上面代码还是有问题,因为上面有两次事务,而第一事务没有提交,所以无效。之后按返回键,预测一下结果?是正确的,正确回到fragment1,fragment2被销毁。
下面再改正重叠问题,上面改为:
fragment2=new Fragment2();
getSupportFragmentManager().beginTransaction().hide(fragment1).add(R.id.container,fragment2).addToBackStack(null).commit();
或者不想那么长,等价改为:
fragment2=new Fragment2();
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
fragmentTransaction.hide(fragment1);
fragmentTransaction.add(R.id.container,fragment2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
这是因为源码返回值基本都还是一个FragmentTransaction,例如hide():
@NonNull
public FragmentTransaction hide(@NonNull Fragment fragment) {
addOp(new Op(OP_HIDE, fragment));
return this;
}
总结:所以hide()和show(),以及加入返回栈都不会影响fragment的生命周期,不会被销毁,replace()方法则另当别论哦。这两个方法我喜欢用来制作一个主页面,点击下面菜单,切换不同的页面,就像QQ那样,刚进入活动时创建这几个fragment页面,然后单机后用hide,show不停切换。
如果有什么问题,欢迎留言交流。
上一篇: 第8章 丰富你的程序,运用手机多媒体