一、Fragment的生命周期
1.Fragment务必选择android.support.v4.app.Fragment中的Fragment.
2.Fragment的生命周期图以及与Activity生命周期的比较。
3.Fragment生命周期方法解释
Fragment中与Activity同名的生命周期方法与Activity是一样的,不过,Fragment还有几个额外的生命周期回调,用于处理与 Activity 的唯一交互,以执行构建和销毁片段 UI 等操作。 这些额外的回调方法是:
onAttach()
在片段已与 Activity 关联时调用(Activity 传递到此方法内)。
onCreateView()
调用它可创建与片段关联的视图层次结构。
onActivityCreated()
在 Activity 的 onCreate() 方法已返回时调用。
onDestroyView()
在移除与片段关联的视图层次结构时调用。
onDetach()
在取消片段与 Activity 的关联时调用。
4.在开发中推荐实现的方法为:
onCreate()
系统会在创建片段时调用此方法。您应该在实现内初始化您想在片段暂停或停止后恢复时保留的必需片段组件。
onCreateView()
系统会在片段首次绘制其用户界面时调用此方法。 要想为您的片段绘制 UI,您从此方法中返回的 View 必须是片段布局的根视图。如果片段未提供 UI,您可以返回 null。
onPause()
系统将此方法作为用户离开片段的第一个信号(但并不总是意味着此片段会被销毁)进行调用。 您通常应该在此方法内确认在当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。
二、Fragment的使用
1、在布局文件中使用
1.新建ListFragment继承Fragment并实现onCreateView()方法返回Fragment的视图。
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_list,container,false);
return view;
}
inflater方法可将布局文件转换为View,inflate() 方法带有三个参数:
R.layout.fragment_list-您想要扩展的布局的资源 ID;
container-将作为扩展布局父项的 ViewGroup。传递 container 对系统向扩展布局的根视图(由其所属的父视图指定)应用布局参数具有重要意义;
false-指示是否应该在扩展期间将扩展布局附加至 ViewGroup(第二个参数)的布尔值。(在本例中,其值为 false,因为系统已经将扩展布局插入 container — 传递 true 值会在最终布局中创建一个多余的视图组。)
2.在Activity的布局文件中添加作为一般控件使用
其中com.example.fragmenttest.ListFragment为刚才写的Fragment,一定要加上id。
2.在Activity中动态添加
1.在Activity的布局文件中为将要添加的Fragment写一个父项容器,通常使用FrameLayout.
2.在Activity中添加
readerFragment = new ReaderFragment();//1.初始化将要添加的Fragment
FragmentManager fm = getSupportFragmentManager();//2.获得Fragment管理者,在当前Activity中调用
FragmentTransaction transaction = fm.beginTransaction();//3.开启事务
//4.使用add()方法添加Fragment,第一个参数为容纳Fragment的容器,第二个参数为Fragment的唯一标识
transaction.add(R.id.linearlayout, readerFragment,"TAG_READER");
transaction.commit();//5.提交事务,否则不生效
三、Fragment与Activity的通信
1.在Fragment中调用getActivity()方法在 Activity 布局中查找视图
TextView tv_main = getActivity().findViewById(R.id.tv_main);
tv_main.setText("在fragment调用activity");
2.在Activity中获得Fragment实例并执行Fragment中的方法
ReaderFragment reader = (ReaderFragment) fm.findFragmentByTag("TAG_READER");
reader.changeText();
静态添加的Fragemnt用findFragmentById(),动态添加的Fragment用findFragmentByTag()。
四、创建对Activity的事件回调
在某些情况下,您可能需要通过片段与 Activity 共享事件。执行此操作的一个好方法是,在片段内定义一个回调接口,并要求宿主 Activity 实现它。 当 Activity 通过该接口收到回调时,可以根据需要与布局中的其他片段共享这些信息。
例如,如果一个应用的 Activity 有两个Fragment — 一个用于显示文章列表(TitleFragment),另一个用于显示文章内容(DetailsFragment)— 那么TitleFragment 必须在列表项被选定后告知 Activity,以便它告知DetailsFragment 显示该文章。 在本例中,
OnArticleSelectedListener接口在TitleFragment中声明
public class TitleFragment extends Fragment {
OnArticleSelectedListener onArticleSelectedListener;
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(int position);
}
...
}
然后,该片段的宿主 Activity 会实现 OnArticleSelectedListener 接口并替代 onArticleSelected(),将来自TitleFragment 的事件通知片段 DetailsFragment。为确保宿主 Activity 实现此接口,TitleFragment 的 onAttach() 回调方法(系统在向 Activity 添加片段时调用的方法)会通过转换传递到 onAttach() 中的 Activity 来实例化.
OnArticleSelectedListener 的强制实现:
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
onArticleSelectedListener = (OnArticleSelectedListener) activity;
}catch (ClassCastException e){
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
如果 Activity 未实现接口,则片段会引发 ClassCastException。实现时,onArticleSelectedListener成员会保留对 Activity 的 OnArticleSelectedListener 实现的引用,以便TitleFragment 可以通过调用 OnArticleSelectedListener 接口定义的方法与 Activity 共享事件。
五、示例
为了将本文阐述的所有内容融会贯通,以下提供了一个示例,其中的 Activity 使用两个片段来创建一个双窗格布局。 下面的 Activity 包括两个片段:一个用于显示李白诗集标题列表,另一个用于从列表中选定时显示其内容。 此外,它还展示了如何根据屏幕配置提供不同的Fragment配置。
1.MainActivity.class
public class MainActivity extends AppCompatActivity implements TitleFragment.OnArticleSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onArticleSelected(int position) {
startNewActivity(position);
}
/**
* 当屏幕竖直时,开启新的Activity来显示内容
* @param position
*/
private void startNewActivity(int position) {
Intent intent = new Intent(this,DetailsActivity.class);
intent.putExtra("position",position);
startActivity(intent);
}
}
2.MainActivity的布局文件为R.layout.activity_main,布局文件有两个,一个用于屏幕竖直显示,一个用于屏幕横向显示;分别放置在不同的文件夹中。
竖直R.layout.activity_main,保存在res/layout/.
横向R.layout.activity_main,保存在res/layout-land/.
3.TitleFragment.java
public class TitleFragment extends Fragment {
private boolean mmDualPane;//判断屏幕是否为横向布局
OnArticleSelectedListener onArticleSelectedListener;
String[] dates = {"静夜思","赠汪伦","独坐敬亭山"};
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
onArticleSelectedListener = (OnArticleSelectedListener) activity;
}catch (ClassCastException e){
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//判断屏幕是否横向并将值赋给mmDualPane
View detailsFrame = getActivity().findViewById(R.id.details);
mmDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.title_fragment, container, false);
ListView listView = view.findViewById(R.id.listview);
listView.setAdapter(new MyAdapter());
return view;
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return dates.length;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
TextView textView = new TextView(getActivity());
textView.setText(dates[position]);
textView.setTextSize(25);
textView.setTextColor(Color.BLACK);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mmDualPane){//屏幕竖直
//回调接口,让宿主Activity开启新的Activity显示内容
onArticleSelectedListener.onArticleSelected(position);
}else {//屏幕横向
//屏幕横向,直接在当前Activity右侧显示内容即可
FragmentTransaction transaction = getFragmentManager().beginTransaction();
DetailsFragment detailsFragment = new DetailsFragment();
Bundle bundle = new Bundle();
bundle.putInt("position",position);
detailsFragment.setArguments(bundle);
transaction.replace(R.id.details,detailsFragment);
transaction.commit();
}
}
});
return textView;
}
}
/**
* 接口,宿主Activity必須实现
*/
public interface OnArticleSelectedListener{
public void onArticleSelected(int position);
}
}
4.DetailsFragment.java
public class DetailsFragment extends Fragment {
private String[] detailsDates = {"静夜思\n" +
"[唐] 李白\n" +
"床前明月光,疑是地上霜。\n" +
"举头望明月,低头思故乡。", "赠汪伦\n" +
"[唐] 李白\n" +
"李白乘舟将欲行,忽闻岸上踏歌声。\n" +
"桃花潭水深千尺,不及汪伦送我情。", "独坐敬亭山\n" +
"[唐] 李白\n" +
"众鸟高飞尽,孤云独去闲。\n" +
"相看两不厌,只有敬亭山。", "无数据"};
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.detatils_fragment, container, false);
TextView tv_details = view.findViewById(R.id.tv_details);
tv_details.setText(detailsDates[getShowPositon()]);
return view;
}
/**
* 获得点击的试题目position,以作相应显示
* @return
*/
private int getShowPositon() {
return getArguments().getInt("position", 3);
}
}
5.DetailsActivity.java
public class DetailsActivity extends AppCompatActivity {
private int position;
private String[] detailsDates = {"静夜思\n" +
"[唐] 李白\n" +
"床前明月光,疑是地上霜。\n" +
"举头望明月,低头思故乡。", "赠汪伦\n" +
"[唐] 李白\n" +
"李白乘舟将欲行,忽闻岸上踏歌声。\n" +
"桃花潭水深千尺,不及汪伦送我情。", "独坐敬亭山\n" +
"[唐] 李白\n" +
"众鸟高飞尽,孤云独去闲。\n" +
"相看两不厌,只有敬亭山。", "无数据"};
private TextView tv_details;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
position = getIntent().getIntExtra("position", 3);
tv_details = (TextView) findViewById(R.id.tv_details);
showDetails(position);
}
private void showDetails(int position) {
tv_details.setText(detailsDates[position]);
}
}
完整Demo下载