Android之Fragment
(一)
-
Faragment有自己的生命周期
-
Fragment依赖于Activity
-
Fragmen通过getActivity()可以获取所在Activity;Activity通过FragmentManager的findFragmentById()或findFragmentbyTag()获取Fragment
-
Fragment和Activity是多对多的关系
MainActivity
1 package com.example.fragmentdemo.UI; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.content.Intent; 6 import android.os.Bundle; 7 import android.view.View; 8 import android.widget.Button; 9 10 import com.example.fragmentdemo.R; 11 12 public class MainActivity extends AppCompatActivity { 13 14 private Button mBtnFragment; 15 16 @Override 17 protected void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 setContentView(R.layout.activity_main); 20 mBtnFragment = (Button)findViewById(R.id.btn_fragment); 21 setListeners(); 22 } 23 24 private void setListeners(){ 25 OnClick onclick = new OnClick(); 26 mBtnFragment.setOnClickListener(onclick); 27 } 28 29 private class OnClick implements View.OnClickListener { 30 31 @Override 32 public void onClick(View v) { 33 Intent intent = null; 34 switch (v.getId()){ 35 case R.id.btn_fragment: 36 intent = new Intent(MainActivity.this,ContainerActivity.class); 37 startActivity(intent); 38 break; 39 default: 40 } 41 } 42 } 43 }
ContainerActivity
1 package com.example.fragmentdemo.UI; 2 3 import android.os.Bundle; 4 import android.view.View; 5 import android.widget.Button; 6 7 import androidx.appcompat.app.AppCompatActivity; 8 import androidx.fragment.app.Fragment; 9 10 import com.example.fragmentdemo.AFragment; 11 import com.example.fragmentdemo.BFragment; 12 import com.example.fragmentdemo.R; 13 14 public class ContainerActivity extends AppCompatActivity { 15 16 private AFragment aFragment; 17 private BFragment bFragment; 18 private Button mBtnChange; 19 20 @Override 21 protected void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.activity_container); 24 mBtnChange = (Button)findViewById(R.id.btn_change); 25 mBtnChange.setOnClickListener(new View.OnClickListener(){ 26 27 @Override 28 public void onClick(View v) { 29 if (bFragment == null){ 30 bFragment = new BFragment(); 31 } 32 getSupportFragmentManager().beginTransaction().replace(R.id.fl_container,bFragment).commitNowAllowingStateLoss(); 33 } 34 }); 35 // 实例化AFragment 36 aFragment = new AFragment(); 37 // 把aFragment添加到Activity中 记得调用commitAllowingStateLoss 38 // getSupportFragmentManager().beginTransaction().add(R.id.fl_container,aFragment).commit(); 39 // 当Fragment出现错误时,使用commit()方法会返回一些错误,而commitAllowingStateLoss()就不会 40 getSupportFragmentManager().beginTransaction().add(R.id.fl_container,aFragment).commitAllowingStateLoss(); 41 // getSupportFragmentManager().beginTransaction().replace()替换 42 // getSupportFragmentManager().beginTransaction().remove()移除 43 } 44 45 }
AFragment
1 package com.example.fragmentdemo; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.os.Bundle; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.TextView; 10 11 import androidx.annotation.NonNull; 12 import androidx.annotation.Nullable; 13 import androidx.fragment.app.Fragment; 14 15 public class AFragment extends Fragment { 16 17 private TextView mTvTitle; 18 private Activity mActivity; 19 20 /** 21 * 返回一个视图文件,相当于activity中的setContentView() 22 */ 23 @Nullable 24 @Override 25 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 View view = inflater.inflate(R.layout.fragment_a,container,false); 27 return view; 28 } 29 30 /** 31 * 当View创建完成之后回调该方法 32 */ 33 @Override 34 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 35 super.onViewCreated(view, savedInstanceState); 36 37 mTvTitle = view.findViewById(R.id.tv_title); 38 } 39 40 }
BFragment
1 package com.example.fragmentdemo; 2 3 import android.os.Bundle; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.TextView; 8 9 import androidx.annotation.NonNull; 10 import androidx.annotation.Nullable; 11 import androidx.fragment.app.Fragment; 12 13 public class BFragment extends Fragment { 14 15 private TextView mTvTitle; 16 17 /** 18 * 返回一个视图文件,相当于activity中的setContentView() 19 */ 20 @Nullable 21 @Override 22 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 23 View view = inflater.inflate(R.layout.fragment_b,container,false); 24 return view; 25 } 26 27 /** 28 * 当View创建完成之后回调该方法 29 */ 30 @Override 31 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 32 super.onViewCreated(view, savedInstanceState); 33 34 mTvTitle = view.findViewById(R.id.tv_title); 35 } 36 }
(二)
-
Fragment中getActivity()为null的问题:当手机应用长期位于后台被回收后,当里面一些异步任务完成后回来getActivity时就为null
-
1 package com.example.fragmentdemo; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.os.Bundle; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 import android.widget.TextView; 10 11 import androidx.annotation.NonNull; 12 import androidx.annotation.Nullable; 13 import androidx.fragment.app.Fragment; 14 15 public class AFragment extends Fragment { 16 17 private TextView mTvTitle; 18 private Activity mActivity; 19 20 /** 21 * 返回一个视图文件,相当于activity中的setContentView() 22 */ 23 @Nullable 24 @Override 25 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 26 View view = inflater.inflate(R.layout.fragment_a,container,false); 27 return view; 28 } 29 30 /** 31 * 当View创建完成之后回调该方法 32 */ 33 @Override 34 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 35 super.onViewCreated(view, savedInstanceState); 36 37 mTvTitle = view.findViewById(R.id.tv_title); 38 if(getActivity() != null){ //判断当前activity是否为null 39 40 }else{ 41 42 } 43 } 44 45 /** 46 * 当Fragment重建或者Fragment与Activity重新建立关系时运行这个方法 47 * @param context 48 */ 49 @Override 50 public void onAttach(Context context) { 51 super.onAttach(context); 52 mActivity = (Activity)context; 53 } 54 55 56 /** 57 * 当activity为null时必然运行了这个方法,就是Fragment与Activity脱离关系 58 */ 59 @Override 60 public void onDetach() { 61 super.onDetach(); 62 } 63 64 /** 65 * Fragment回收 66 */ 67 @Override 68 public void onDestroy() { 69 super.onDestroy(); 70 // 取消异步任务 71 } 72 }
-
-
向Fragment传递参数
1 //ContainerActivity: 2 3 aFragment = AFragment.newInstance("我是参数");//传递参数给Fragment
1 //AFragment: 2 3 4 /** 5 *传参 6 */ 7 public static AFragment newInstance(String title){ 8 AFragment fragment = new AFragment(); 9 Bundle bundle = new Bundle(); 10 bundle.putString("title",title); 11 fragment.setArguments(bundle); //将bundle传入fragment;即便fragment重构,setArguments()方法也会运用反射机制将title重新放入fragment 12 return fragment; 13 } 14 15 16 17 /** 18 * 当View创建完成之后回调该方法 19 */ 20 @Override 21 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 22 super.onViewCreated(view, savedInstanceState); 23 // if(getActivity() != null){ //判断当前activity是否为null 24 // }else{} 25 mTvTitle = view.findViewById(R.id.tv_title); 26 if(getArguments() != null){ 27 mTvTitle.setText(getArguments().getString("title")); 28 } 29 }
(三)
-
Fragment回退栈
1 AFragment: 2 3 mBtnChange = view.findViewById(R.id.btn_change); 4 mBtnReset = view.findViewById(R.id.btn_reset); 5 mBtnChange.setOnClickListener(new View.OnClickListener() { 6 @Override 7 public void onClick(View v) { 8 if (bFragment == null) { 9 bFragment = new BFragment(); 10 } 11 Fragment fragment = getFragmentManager().findFragmentByTag("a"); 12 if (fragment != null) { 13 // 隐藏aFragment,再添加bFragment 14 getFragmentManager().beginTransaction().hide(fragment).add(R.id.fl_container, bFragment).addToBackStack(null).commit(); 15 } else { 16 // 在commitNowAllowingStateLoss()方法之前加addToBackStack(null)将AFragment添加到回退栈里面,这样跳到BFragment再按返回键时,返回到AFragment,而不是MainActivity 17 // replace可以理解为先remove再add,导致前一个fragment的视图没有被保存下来,虽然重新创建fragment视图了,但其视图内容也被重新创建了 18 getFragmentManager().beginTransaction().replace(R.id.fl_container, bFragment).addToBackStack(null).commit(); 19 } 20 } 21 });
(四)
-
Fragment和Activity的通信
- 方法一:
1 AFragment 2 3 mBtnMessage.setOnClickListener(new View.OnClickListener() { 4 @Override 5 public void onClick(View v) { 6 // 通过getActivity()获得Activity,然后将其转换成ContainerActivity,调用它的setData()方法 7 // 该方法能够向Activity传参,但不推荐 8 ((ContainerActivity)getActivity()).setData("你好"); //方法一 9 } 10 });
1 ContainerActivity 2 3 public void setData(String text){ 4 mTvTitle.setText(text); 5 }
这个方法可行但不推荐使用
-
方法二:在activity中实现fagment中声明的接口,通过回调接口来实现数据的传递
1 AFragment 2 3 4 /** 5 * 接口 6 */ 7 public interface IOnMessageClick{ 8 void onClick(String text); 9 } 10 11 /** 12 * 当Fragment重建或者Fragment与Activity重新建立关系时运行这个方法 13 * 14 * @param context 15 */ 16 @Override 17 public void onAttach(Context context) { 18 super.onAttach(context); 19 // mActivity = (Activity)context; 20 try{ 21 listener = (IOnMessageClick) context; 22 } catch (ClassCastException e) { 23 throw new ClassCastException("Activity 必须实现IOnMessageClick接口"); 24 } 25 26 } 27 28 mBtnMessage.setOnClickListener(new View.OnClickListener() { 29 @Override 30 public void onClick(View v) { 31 // 通过getActivity()获得Activity,然后将其转换成ContainerActivity,调用它的setData()方法 32 // 该方法能够向Activity传参,但不推荐 33 // ((ContainerActivity)getActivity()).setData("你好"); //方法一 34 listener.onClick("你好"); 35 } 36 });
1 ContainerActivity 2 3 4 @Override 5 public void onClick(String text) { 6 mTvTitle.setText(text); 7 }