原文地址:https://www.raywenderlich.com/149112/android-fragments-tutorial-introduction
Fragment生命周期
- onAttach 当fragment被附加到宿主Activity中时触发
- onCreate 当一个新的fragment实例初始化的时候,发生在attachs之后
- onCreateView 当一个fragment创建他的视图层级的时候引用,将会被添加进activity的视图层级中
- onActivityCreated 当fragments的宿主activity完成自己的onCreate事件之后执行
- onStart 当fragment是可见的,fragment在其宿主activity start之后执行自己的start方法,而且是立即执行
- onResume 当fragment是可见的和可交互的,fragment在其宿主activity恢复之后恢复,并且是立即恢复
片段还没有完成,当你移除一个fragment的时候,会执行如下事件:
- onPause 当一个fragment不再需要交互的时候,这个事件发生在当一个fragment被移除掉或者替换掉或者activity执行pause事件的时候
- onStop 当一个fragment不可见的时候,这个事件发生在一个fragment被移除掉或者替换掉或者fragment的宿主activity执行stop方法的时候
- onDestroyView 当在onCreateView中创建的视图资源从activity的视图层级中销毁时触发该事件
- onDestroy 当fragment做最后的清理的时候
- onDetach 当fragment从activity中分离的时候
如上所示,fragment的生命周期和activity的生命周期相互交织,但是也有额外的事件
v4 Support Library
The v4 Support Library提供fragment在不低于3.0的设备上的实现,其实现类在android.support.v4.app.Fragment
包下
如果你的app运行在4.0+的设备上,你就需要使用这个支持的fragment
创建一个Fragment
//1
public class RageComicDetailsFragment extends Fragment{
//2
public static RageComicDetailsFragment newInstance(){
return new RageComicDetailsFragment();
}
//3
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
return inflater.inflate(R.layout.fragment_rage_comic_details, container, false);
}
}
- 声明一个Fragment的子类RageComicDetailsFragment
- 提供一个创建fragment新实例的方法
- 创建由fragment控制的视图层次结构
inflate方法的第三个参数指定是否将fragment添加到container中,container是保存fragment视图层级的父视图,要设置这个参数为false
,FragmentManager将负责把fragment添加到container中。
每个activity都有一个FragmentManager
,用来管理他自己的Fragments,他还提供了一个可以添加和移除fragment的接口
你会注意到RageComicDetailsFragment有一个工厂实例方法newInstance()
,他没有任何的构造函数。
为什么需要一个工厂方法而不是一个构造函数
首先,因为你没有定义任何的构造函数,编译器会自动生成一个没有参数的空的构造函数。
如果你声明了一个非空的构造函数但是没有声明一个空构造函数的话,Lint就会给你一个错误:
现在当你运行你的陈旭的时候,将会得到一个相当严重的异常
添加一个Fragment
你可以将你的fragment添加到宿主activity的XML布局中
动态添加一个Fragment
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.root_layout,RageComicDetailsFragment.newInstance(),"rageComicList")
.comit();
}
}
FragmentManager通过FragmentTransaction实现Fragment的添加和删除等功能。
同Activity通信
当Fragment中的选项被选择的时候,需要让activity知道哪个被选择了
首先,我们在RageComicListFragment中添加如家接口代码:
public interface OnRageComicSelected{
void onRageComicSelected(int imageResId, String name,String description,String url);
}
定义一个监听接口来监听fragment,activity将实现这个接口,当item被选择的时候,fragment将会调用onRageComicSelected()方法,将选项传给activity。
在RageComicListFragment中添加如下代码:
private OnRageComicSelected mListener;
在onAttach()
,添加如下代码在super.onAttach(Context)
下面
if(context instanceof OnRageComicSelected){
mListener = (OnRageComicSelected)context;
}else{
throw new ClassCastException(context.toString()+" must implement OnRageComicSelected");
}
在onBindViewHolder()
方法中,添加如下代码
viewHolder.itemView.setOnclickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
mListener.onRageComicSelected(imageResId,name,description,url);
}
});
让MainActivity实现OnRageComicSelected接口。
Fragment参数和事务
打开RageComicDetailsFragment然后添加如下属性:
private static final String ARGUMENT_IMAGE_RES_ID="imageResId";
private static final String ARGUMENT_NAME="name";
private static final String ARGUMENT_DESCRIPTION="description";
private static final String ARGUMENT_URL="url";
public static RageComicDetailsFragment newInstance(int imageResId,String name,String description,String url){
final Bundle args = new Bundle();
args.putInt(ARGUMENT_IMAGE_RES_ID, imageResId);
args.putString(ARGUMENT_NAME, name);
args.putString(ARGUMENT_DESCRIPTION, description);
args.putString(ARGUMENT_URL, url);
final RageComicDetailsFragment fragment = new RageComicDetailsFragment();
fragment.setArguments(args);
return fragment;
}
可以通过getArguments
和setArguments
来初始化参数,arguments实际上就是一个Bundle用来存储key-value键值对,就像Activity.onSaveInstanceState
中的Bundle一样。
当你创建和填充参数的时候,调用setArguments,当你需要使用值得时候,调用getArguments。
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_rage_comic_details, container, false);
final ImageView imageView = (ImageView) view.findViewById(R.id.comic_image);
final TextView nameTextView = (TextView) view.findViewById(R.id.name);
final TextView descriptionTextView = (TextView) view.findViewById(R.id.description);
final Bundle args = getArguments();
imageView.setImageResource(args.getInt(ARGUMENT_IMAGE_RES_ID));
nameTextView.setText(args.getString(ARGUMENT_NAME));
final String text = String.format(getString(R.string.description_format), args.getString
(ARGUMENT_DESCRIPTION), args.getString(ARGUMENT_URL));
descriptionTextView.setText(text);
return view;
}
现在当你点击一个条目之后需要创建和显示RageComicDetailsFragment的时候,需要在MainActivity的onRageComicSelected方法中添加如下代码:
@Override
public void onRageComicSelected(int imageResId, String name, String description, String url) {
final RageComicDetailsFragment detailsFragment =
RageComicDetailsFragment.newInstance(imageResId, name, description, url);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.root_layout, detailsFragment, "rageComicDetails")
.addToBackStack(null)
.commit();
}