在開發中ViewPager+fragment,包括緩存pager或者fragment中一些問題,什麼時候該緩存銷毀page,什麼時候緩存銷毀fragment問題
FragmentPagerAdapter,FragmentStatePagerAdapter的差別和适用場景
FragmentPagerAdapter
1、通過offscreenPageLimit來控制page container的cache數量 n*2+1;
2、當加載的page超出cache count會用FragmentManager來釋放fragment
3、被釋放的fragment實際上不會被完全回收,因為沒有調用onDestory(),當再次回到這個page時也沒有調用onCreate();
4、當fragment被顯示在螢幕上時,setUserVisibleHint為true,不顯示時為false.
适用于:
page是固定的,并且數量比較少,因為fragment不會被完全回收
FragmentStatePagerAdapter
其他三點都一樣,不同的是
被釋放的fragment會被完全回收,調用了onDestory()的方法;
适用于:
比較多的fragment,保證回收,清理記憶體
1、首先明确Fragment的生命周期
如果用ViewPager+fragment,首先應該明确fragment的生命周期,這個fragment什麼時候開始建立,什麼時候建立完成,什麼時候建立view,什麼時候可以加載資料。
幾個重要容易模糊的生命周期
1、onAttach() 當一個fragment第一次綁定到它所屬的activity中
/**
* Called when a fragment is first attached to its activity.
* {@link #onCreate(Bundle)} will be called after this.
* <p>Deprecated. See {@link #onAttach(Context)}.
*/
@Deprecated
public void onAttach(Activity activity) {
mCalled = true;
}
2、onCreate()它所屬的activity正在建立中,并沒有建立完成
/**
* Called to do initial creation of a fragment. This is called after
* {@link #onAttach(Activity)} and before
* {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
*
* <p>Note that this can be called while the fragment's activity is
* still in the process of being created. As such, you can not rely
* on things like the activity's content view hierarchy being initialized
* at this point. If you want to do work once the activity itself is
* created, see {@link #onActivityCreated(Bundle)}.
*
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
public void onCreate(@Nullable Bundle savedInstanceState) {
mCalled = true;
}
3、onCreateView():可以把fragment的布局填充到view中,傳回fragment的UI布局。
/**
* Called to have the fragment instantiate its user interface view.
* This is optional, and non-graphical fragments can return null (which
* is the default implementation). This will be called between
* {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}.
*
* <p>If you return a View from here, you will later be called in
* {@link #onDestroyView} when the view is being released.
*
* @param inflater The LayoutInflater object that can be used to inflate
* any views in the fragment,
* @param container If non-null, this is the parent view that the fragment's
* UI should be attached to. The fragment should not add the view itself,
* but this can be used to generate the LayoutParams of the view.
* @param savedInstanceState If non-null, this fragment is being re-constructed
* from a previous saved state as given here.
*
* @return Return the View for the fragment's UI, or null.
*/
@Nullable
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return null;
}
4、onActivityCreated():這時候activity建立完成,并且fragment布局已經填充進去。
/**
* Called when the fragment's activity has been created and this
* fragment's view hierarchy instantiated. It can be used to do final
* initialization once these pieces are in place, such as retrieving
* views or restoring state. It is also useful for fragments that use
* {@link #setRetainInstance(boolean)} to retain their instance,
* as this callback tells the fragment when it is fully associated with
* the new activity instance. This is called after {@link #onCreateView}
* and before {@link #onViewStateRestored(Bundle)}.
*
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
mCalled = true;
}
5、onDestroyView:銷毀目前的view也就是填充的布局
/**
* Called when the view previously created by {@link #onCreateView} has
* been detached from the fragment. The next time the fragment needs
* to be displayed, a new view will be created. This is called
* after {@link #onStop()} and before {@link #onDestroy()}. It is called
* <em>regardless</em> of whether {@link #onCreateView} returned a
* non-null view. Internally it is called after the view's state has
* been saved but before it has been removed from its parent.
*/
public void onDestroyView() {
mCalled = true;
}
6、onDestroy():銷毀目前的fragment
/**
* Called when the fragment is no longer in use. This is called
* after {@link #onStop()} and before {@link #onDetach()}.
*/
public void onDestroy() {
mCalled = true;
//Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
// + " mLoaderManager=" + mLoaderManager);
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
mLoaderManager.doDestroy();
}
}
2、ViewPager中的擴充卡使用FragmentPagerAdapter
package com.example.yu.viewpager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import com.example.yu.baseactivity.R;
import com.example.yu.viewpager.fragment.Fragment1;
import com.example.yu.viewpager.fragment.Fragment2;
import com.example.yu.viewpager.fragment.Fragment3;
import com.example.yu.viewpager.fragment.Fragment4;
import com.example.yu.viewpager.fragment.Fragment5;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends FragmentActivity {
private ViewPager viewPager;
private MyFragemtAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewPager);
List<Fragment> fragments = new ArrayList<Fragment>();
fragments.add(new Fragment1());
fragments.add(new Fragment2());
fragments.add(new Fragment3());
fragments.add(new Fragment4());
fragments.add(new Fragment5());
adapter = new MyFragemtAdapter(getSupportFragmentManager(), fragments);
//設定緩存page的個數 *n+;
viewPager.setOffscreenPageLimit();
viewPager.setAdapter(adapter);
}
class MyFragemtAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragments;
public MyFragemtAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
}
}
Fragment1示例代碼如下(其他四個也都一樣)
package com.example.yu.viewpager.fragment;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.yu.baseactivity.R;
/**
* Created by yu on 2016/6/12.
*/
public class Fragment1 extends Fragment {
public static final String TAG = "Fragment1";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1, container, false);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.i(TAG, "fragment is onDestroyView()");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "fragment is onDestroy()");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "fragment is onCreate()");
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i(TAG, "fragment is onActivityCreated()");
}
}
3、ViewPager中的擴充卡使用FragmentStatePagerAdapter
其他代碼都不動,隻修改擴充卡類型為FragmentStatePagerAdapter
class MyFragemtAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragments;
public MyFragemtAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
}
從Log日志分析