Activity 的生命周期我们知道了,Fragment 的生命周期我们也知道了,那么当在 Activity 中嵌套 Frgment 的时候,它们两者的生命周期的执行顺序又是如何的呢?下面我们通过一个实例来看看。
下面是我们想要的效果:
整个 UI 的布局是这样的:一个 Activity 里面,左边是 ListView,右边是 Fragment,点击左边对应的选项,就会在右边的 Fragment 显示该选项的详细信息。
XML 文件
1. 首先是主界面布局,activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list_view"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_marginTop="16dp" />
<FrameLayout
android:id="@+id/frame_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
2. Fragment 的布局,fragment_large.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textColor="#FF7F00"
android:textSize="24sp" />
<ImageView
android:id="@+id/iv_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:scaleType="centerCrop" />
</LinearLayout>
3. ListView 的样式,item_listview.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_small"
android:layout_width="60dp"
android:layout_height="60dp" />
<TextView
android:id="@+id/tv_small"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_marginLeft="10dp"
android:gravity="center" />
</LinearLayout>
Java 代码
1. 主界面代码,MainActivity.java:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Lifecycle";
private int[] imageIds = {R.drawable.aries, R.drawable.taurus, R.drawable.gemini,
R.drawable.cancer, R.drawable.leo, R.drawable.virgo, R.drawable.libra,
R.drawable.scorpio, R.drawable.sagittarius, R.drawable.capricorn,
R.drawable.aquarius, R.drawable.pisces, R.drawable.fuck_off};
private String[] titles = {"白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座",
"天秤座", "天蝎座", "射手座", "摩羯座", "水瓶座", "双鱼座", "Surprise"};
private MyListener myListener;
private MyAdapter adapter;
public MyListener getMyListener() {
return myListener;
}
public void setMyListener(MyListener myListener) {
this.myListener = myListener;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v(TAG, "MainActivity --> onCreate");
init();
replaceFragment();
}
@Override
protected void onStart() {
super.onStart();
Log.v(TAG, "MainActivity --> onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.v(TAG, "MainActivity --> onResume");
}
@Override
protected void onRestart() {
super.onRestart();
Log.v(TAG, "MainActivity --> onRestart");
}
@Override
protected void onPause() {
super.onPause();
Log.v(TAG, "MainActivity --> onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.v(TAG, "MainActivity --> onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.v(TAG, "MainActivity --> onDestroy");
}
/**
* 初始化
*/
private void init() {
// 准备数据
List<Integer> imgIdList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
for (int i = 0; i < imageIds.length; i++) {
imgIdList.add(imageIds[i]);
titleList.add(titles[i]);
}
// 初始化布局中的控件
ListView listView = (ListView) findViewById(R.id.list_view);
// 创建适配器
adapter = new MyAdapter(this, R.layout.item_listview, imgIdList, titleList);
// 设置适配器
listView.setAdapter(adapter);
// 设置 ListView 点击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
myListener.onSend(titles[position], imageIds[position]);
adapter.setCurrentItem(position);
adapter.notifyDataSetInvalidated();
}
});
}
/**
* 替换 Fragment
*/
private void replaceFragment() {
LargeFragment fragment = new LargeFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout, fragment).commit();
}
}
2. Fragment 代码,LargeFragment.java:
/**
* Created by Monkey.C on 2016/6/27.
*/
public class LargeFragment extends Fragment {
private static final String TAG = "Lifecycle";
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.v(TAG, "LargeFragment --> onAttach");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(TAG, "LargeFragment --> onCreate");
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_large, container, false);
final TextView tv = (TextView) view.findViewById(R.id.tv_large);
final ImageView iv = (ImageView) view.findViewById(R.id.iv_large);
// 通过获取 MainActivity 的实例,从而调用 MainActivity 里的方法
MainActivity activity = (MainActivity) getActivity();
activity.setMyListener(new MyListener() {
@Override
public void onSend(String title, int imgId) {
tv.setText(title);
iv.setImageResource(imgId);
}
});
Log.v(TAG, "LargeFragment --> onCreateView");
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.v(TAG, "LargeFragment --> onActivityCreated");
}
@Override
public void onStart() {
super.onStart();
Log.v(TAG, "LargeFragment --> onStart");
}
@Override
public void onResume() {
super.onResume();
Log.v(TAG, "LargeFragment --> onResume");
}
@Override
public void onPause() {
super.onPause();
Log.v(TAG, "LargeFragment --> onPause");
}
@Override
public void onStop() {
super.onStop();
Log.v(TAG, "LargeFragment --> onStop");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.v(TAG, "LargeFragment --> onDestroyView");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v(TAG, "LargeFragment --> onDestroy");
}
@Override
public void onDetach() {
super.onDetach();
Log.v(TAG, "LargeFragment --> onDetach");
}
}
3. 定义一个接口,用于 Activity 向 Fragment 传递数据,MyLinstener.java:
/**
* Created by Monkey.C on 2016/6/27.
*/
/**
* 定义一个接口,该接口有一个 onSend() 方法,
* 用于 MainActivity 向 LargeFragment 传递数据
* 注意:在 MainActivity 定义该接口的对象,但并不实现该接口,
* 而是在 LargeFragment 里实现该接口。
* 发送方本身并不实现接口,而是由接收方去实现该接口。
*/
public interface MyListener {
void onSend(String title,int imgId);
}
4. 自定义适配器,MyAdapter.java:
/**
* Created by Monkey.C on 2016/6/27.
*/
public class MyAdapter extends BaseAdapter {
private Context context;
private int resourceId;
private List<Integer> imgIdList;
private List<String> titleList;
private int currentItem = -1;
// 设置当前选中项
public void setCurrentItem(int currentItem) {
this.currentItem = currentItem;
}
/**
* @param context 当前上下文
* @param resourceId 布局文件,用于控制 AdapterView 的外观
* @param imgIdList 图片 id 集合
* @param titleList 标题集合
*/
public MyAdapter(Context context, int resourceId, List<Integer> imgIdList, List<String> titleList) {
this.context = context;
this.resourceId = resourceId;
this.imgIdList = imgIdList;
this.titleList = titleList;
}
@Override
public int getCount() {
return titleList.size();
}
@Override
public Object getItem(int position) {
return titleList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
// 判断 convertView 是否为空
if (convertView == null) {
// LayoutInflater,布局加载器,用来加载从外部传进来的布局
convertView = LayoutInflater.from(context).inflate(resourceId, null);
// 实例化 ViewHolder
viewHolder = new ViewHolder();
// 将控件实例存储在 ViewHolder 中
viewHolder.iv = (ImageView) convertView.findViewById(R.id.iv_small);
viewHolder.tv = (TextView) convertView.findViewById(R.id.tv_small);
// 将 ViewHolder 存储在 convertView 中,即缓存布局
convertView.setTag(viewHolder);
} else {
// 取出 ViewHolder 中的缓存
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.iv.setImageResource(imgIdList.get(position));
viewHolder.tv.setText(titleList.get(position));
// 设置选中项颜色
if (currentItem == position) {
convertView.setBackgroundColor(context.getResources().getColor(R.color.selected));
} else {
convertView.setBackgroundColor(context.getResources().getColor(R.color.unselected));
}
return convertView;
}
/**
* 内部类,用来缓存控件实例
*/
class ViewHolder {
ImageView iv;
TextView tv;
}
}
效果演示:
1. 运行程序:
此时的 logcat:
2. 点击 ListView 的不同项,此时的 logcat 还是和上面一样,没有变化:
3. 按下主页键,回到桌面,此时的 logcat:
4. 按下多任务键,找到我们的程序,重新回到程序,此时的 logcat:
5. 按下返回键,退出程序,此时的 logcat:
可以看到此时的 Activity 和 Fragment 已经销毁了。
6. 重新运行程序,将重新执行 1 的过程:
总结
从上面的实例中可以看到,当在 Activity 中嵌套 Fragment 的时候,两者的生命周期的执行顺序是相互交叉的,弄清楚两者生命周期执行顺序的先后是很重要的,尤其是在涉及到两者之间数据的传递的时候。
源码下载:点这里(密码:e8bf)