前言
最近換了新工作,一直寫業務,寫的過程中碰到了viewPager結合Fragment的使用的場景,但是發現自己對此時Fragment的生命週期理解並不到位,在此做一下記錄。
代碼和佈局文件
ActivityForViewPager.java
package com.xol.viewpagerfragment;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
/**
* Created by wwzhang on 2019/1/24
*/
public class ActivityForViewPager extends AppCompatActivity {
private ViewPager viewPager;
private TabLayout tabLayout;
private String tabs[] = {"A", "B", "C", "D", "E"};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_for_viewpager);
initView();
}
private void initView() {
viewPager = (ViewPager) findViewById(R.id.vp_content);
tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), tabs));
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
/**
* fagment
*/
public static class ViewPagerFragment extends Fragment {
private static final String TAG = "ViewPagerFragment";
private String tab;
public static Fragment createFragment(Bundle bundle) {
Fragment fragment = new ViewPagerFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onAttach(Context context) {
tab = getArguments().getString("tab");
super.onAttach(context);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated: " + tab);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: " + tab);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: " + tab);
TextView textView = new TextView(container.getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER;
textView.setPadding(25, 25, 25, 25);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(params);
textView.setText(tab);
return textView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onViewCreated: " + tab);
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onStart() {
Log.d(TAG, "onStart: " + tab);
super.onStart();
}
@Override
public void onResume() {
Log.d(TAG, "onResume: " + tab);
super.onResume();
}
@Override
public void onPause() {
Log.d(TAG, "onPause: " + tab);
super.onPause();
}
@Override
public void onStop() {
Log.d(TAG, "onStop: " + tab);
super.onStop();
}
@Override
public void onDestroyView() {
Log.d(TAG, "onDestroyView: " + tab);
super.onDestroyView();
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: " + tab);
super.onDestroy();
}
@Override
public void onDetach() {
Log.d(TAG, "onDetach: " + tab);
super.onDetach();
}
}
/**
* 適配器
*/
public static class ViewPagerAdapter extends FragmentPagerAdapter {
private String[] tabs;
public ViewPagerAdapter(FragmentManager fm, String[] tabs) {
super(fm);
this.tabs = tabs;
}
@Override
public Fragment getItem(int position) {
Bundle bundle = new Bundle();
bundle.putString("tab", tabs[position]);
// return null;
return ViewPagerFragment.createFragment(bundle);
}
@Override
public int getCount() {
return tabs.length;
}
@Override
public CharSequence getPageTitle(int position) {
return tabs[position];
}
}
}
activity_for_viewpager.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="vertical">
<TextView
android:padding="16dp"
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="ViewPager" />
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="@+id/vp_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
運行結果
Fragment典型週期圖
viewPager 從A滑倒B輸出日誌
01-24 14:10:37.001 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreate: A
01-24 14:10:37.002 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreate: B
onCreateView: A
01-24 14:10:37.004 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onViewCreated: A
onActivityCreated: A
01-24 14:10:37.005 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onStart: A
onResume: A
onCreateView: B
01-24 14:10:37.006 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onViewCreated: B
onActivityCreated: B
01-24 14:10:37.008 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onStart: B
onResume: B
//上面爲第一次打開該Activity日誌輸出
01-24 14:10:40.036 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreate: C
01-24 14:10:40.038 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreateView: C
01-24 14:10:40.039 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onViewCreated: C
onActivityCreated: C
onStart: C
onResume: C
// 上面爲viewPager滑動到B Fragment的日誌輸出
01-24 14:10:40.812 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreate: D
01-24 14:10:40.813 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onPause: A
onStop: A
01-24 14:10:40.814 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onDestroyView: A
01-24 14:10:40.815 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreateView: D
01-24 14:10:40.817 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onViewCreated: D
onActivityCreated: D
01-24 14:10:40.818 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onStart: D
onResume: D
// 上面爲viewPager滑動到C Fragment的日誌輸出
01-24 14:10:41.618 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreate: E
onPause: B
01-24 14:10:41.619 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onStop: B
onDestroyView: B
01-24 14:10:41.620 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onCreateView: E
01-24 14:10:41.622 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onViewCreated: E
01-24 14:10:41.623 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onActivityCreated: E
onStart: E
01-24 14:10:41.624 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onResume: E
// 上面爲viewPager滑動到D Fragment的日誌輸出
01-24 14:10:42.720 1805-1805/com.xol.viewpagerfragment D/ViewPagerFragment: onPause: C
onStop: C
onDestroyView: C
// 上面爲viewPager滑動到E Fragment的日誌輸出
日誌分析
- 打開activity,viewPager沒有滑動的時候,由於PagerFragmentAdapter 默認緩存三個Fragment(當前頁和左右頁面) 第一次當前頁面爲A Fragment 緩存右邊頁面爲B Fragment;故開始日誌輸出爲A-onCreate-onCreateView-onViewCreated-onActivityCreated-onStart-onResume B-onCreate-onCreateView-onViewCreated-onActivityCreated-onStart-onResume
- 當viewPager滑動到B Fragment時候,由於默認緩存三個Fragment,會預先生成C Fragment,故日誌輸出爲C-onCreate-onCreateView-onViewCreated-onActivityCreated-onStart-onResume
- 當viewPager滑動到C Fragment,會預先生成D Fragment,移除A-Fragment(內存中依然存在);故日誌輸出爲D-onCreate-onCreateView-onViewCreated-onActivityCreated-onStart-onResume A-onPause-onStop-onDestroyView
- 當viewPager由C Fragment 動到B Fragment時,A Fragment 會走 onCreateView-onViewCreated-onActivityCreated-onStart-onResume
總結
ViewPager 結合PagerFragmentAdapter滑動的過程中,默認會生成三個Fragment(當在viewPager開始和結尾的時候默認只會生成兩個Fragment)包括當前Fragment和左右位置的Fragment,並且在滑動的過程中,會預先生成下一個Fragment,並銷燬多餘的Fragment,列當滑到C Fragment 的時候,A Fragment 會從view層面銷燬,但並不會走Fragment的onDestroy和onDetach週期方法,當我們反向滑動,並重新預加載A Fragment時,此時 A Fragment 並不會走onAttach 和 onCreate方法,只會走onCreateView-onViewCreated-onActivityCreated-onStart-onResume
此時若想複用之前的View 可在內存中保存一個Fragment的根view,做非空判斷,去複用已經創建過的view Fragment代碼如下:
public static class ViewPagerFragment extends Fragment {
private static final String TAG = "ViewPagerFragment";
private String tab;
private View mRootView;
public static Fragment createFragment(Bundle bundle) {
Fragment fragment = new ViewPagerFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onAttach(Context context) {
tab = getArguments().getString("tab");
Log.d(TAG, "onAttach: "+tab);
super.onAttach(context);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated: " + tab);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: " + tab);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: " + tab);
if(mRootView==null) {
TextView textView = new TextView(container.getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER;
textView.setPadding(25, 25, 25, 25);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(params);
textView.setText(tab);
mRootView =textView;
}
return mRootView;
}
}
點擊返回鍵關閉Activity日誌輸出
01-24 14:29:39.719 3087-3087/com.xol.viewpagerfragment D/ViewPagerFragment: onPause: D
01-24 14:29:39.721 3087-3087/com.xol.viewpagerfragment D/ViewPagerFragment: onPause: E
01-24 14:29:40.567 3087-3087/com.xol.viewpagerfragment D/ViewPagerFragment: onStop: D
onStop: E
01-24 14:29:40.568 3087-3087/com.xol.viewpagerfragment D/ViewPagerFragment: onDestroyView: D
01-24 14:29:40.570 3087-3087/com.xol.viewpagerfragment D/ViewPagerFragment: onDestroy: D
onDetach: D
onDestroyView: E
onDestroy: E
onDetach: E
01-24 14:29:40.571 3087-3087/com.xol.viewpagerfragment D/ViewPagerFragment: onDestroy: A
onDetach: A
onDestroy: B
onDetach: B
onDestroy: C
01-24 14:29:40.572 3087-3087/com.xol.viewpagerfragment D/ViewPagerFragment: onDetach: C
- 當我們關閉Fragment的宿主Activity的時候,此時,所有生成的Fragment都會走 onDestroy-onDetach方法。
總結
我們在結合ViewPager和FragmentPagerAdapter使用的時候,可以在Fragment的OnDestory或OnDetach方法中回收Fragment中的資源。
希望對您有所幫助