發(fā)現(xiàn)問題 (FragmentPageAdapter)
因?yàn)镕ragmentPageAdapter在超出緩存的頁面后,只是將fragment中的mView設(shè)置為空,但是fragment對象的引用還在,由于我使用了ButterKnife,在fragment的對象中有個(gè)imageView的成員變量,導(dǎo)致imageView無法回收.而如果使用了FragmentStatePagerAdapter,則會將fragment的直接置空,不會出現(xiàn)內(nèi)存釋放不了的問題
FragmentPageAdapter 與FragmentStatePageAdapter的區(qū)別
FragmentPageAdapter的源碼
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);//因?yàn)閒ragment實(shí)例沒有被真正釋放,所以可以直接attach效率高
} else {
fragment = getItem(position);//初始化頁面的時(shí)候拿到fragment的實(shí)例
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));//add上去
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);//并沒有真正釋放fragment對象只是detach
}
FragmentStatePageAdapter的destroy
@Override
public Object instantiateItem(ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);//fragment被釋放后這里得到的null值
if (f != null) {
return f;
}
}
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = getItem(position);//fragment被釋放后或者是初次進(jìn)入頁面拿到新的Fragment實(shí)例
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment);//新的Fragment實(shí)例 是add上去的
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment)object).getView());
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);//真正釋放了fragment實(shí)例
mCurTransaction.remove(fragment);
}
FragmentPageAdapter解決方案
在Fragment-->onDestroyView()的時(shí)候,將含有bitmap的imageView移除.
((ViewGroup) imageView.getParent()).removeView(imageView);
引用自 android - FragmentStatePagerAdapter OutOfMemoryError - Stack Overflow
protected void onDestroy(){
super.onDestroy();
unbindDrawables(getView()); // <---This should be the ID of this fragments (ScreenSlidePageFragment) layout
}
private void unbindDrawables(View view){
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}