Fragment中getActivity()為空的最佳解決方案
今天程式碼君遇到一個坑,在 Fragment 中getActivity()或getContext()返回為空,一直很懵逼,Activity都沒有銷燬掉,為何Activity獲取會報空指標?
實現的功能是:一個Activity 裡面包含多個Fragment模組,使用者自由選擇Fragment模組,然後展示使用者選擇的模組
實現:一個Activity+mFragmentPagerAdapter+BaseFragment ,使用者選擇完,更新ListFragment,然後
重新整理介面卡mPagerAdapter.notifyDataSetChanged();
一、網上資料查詢
大多數情況下的原因:你在呼叫了getActivity()時,當前的Fragment已經onDetach()
了宿主Activity。比如:你在pop了Fragment之後,該Fragment的非同步任務仍然在執行,並且在執行完成後呼叫了getActivity()方法,這樣就會空指標。
解決辦法:
在Fragment基類裡設定一個Activity mActivity的全域性變數,在onAttach(Activity activity)裡賦值,使用mActivity代替getActivity(),保證Fragment即使在onDetach後,仍持有Activity的引用(有引起記憶體洩露的風險,但是相比空指標閃退,這種做法“安全”些
public class BaseFragment extends Fragment { private Activity activity; public Context getContext() { if (activity == null) { return MyApplication.getInstance(); } return activity; } @Override public void onAttach(Context context) { super.onAttach(context); activity = getActivity(); } }
二、最佳解決方案
如果你去百度搜索,大部分是上面的答案,且不說有沒有效果(實際是沒效果),光是解決方案,就不是很好,因為這樣持續引用,會出現記憶體洩漏的風險,這就是為什麼國內技術資源千篇一律,都是大家互相拷貝,都不去驗證有沒有效果!
下面是程式碼君Google的解決方案,只需要把你寫的PagerAdapter繼承下面的SmartFragmentStatePagerAdapter就不會出現問題
/* Extension of FragmentStatePagerAdapter which intelligently caches all active fragments and manages the fragment lifecycles. Usage involves extending from SmartFragmentStatePagerAdapter as you would any other PagerAdapter. */ public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter { // Sparse array to keep track of registered fragments in memory private SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>(); public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); } // Register the fragment when the item is instantiated @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment) super.instantiateItem(container, position); registeredFragments.put(position, fragment); return fragment; } // Unregister when the item is inactive @Override public void destroyItem(ViewGroup container, int position, Object object) { registeredFragments.remove(position); super.destroyItem(container, position, object); } // Returns the fragment for the position (if instantiated) public Fragment getRegisteredFragment(int position) { return registeredFragments.get(position); } }
為何會出現空指標,大致原因是我在每次使用者選擇完Fragment,我都會從新new 一個Fragment,但是之前的Fragment在PagerAdapter上還存在,從而導致第二次new 的Fragment再去getActivity就為空指標了
