項目老代碼裡有個bug,關于FragmentPagerAdapter的,在Activity的onNewIntent裡面調用pager中的某個fragment的方法導緻空指針崩潰:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
getIntent().putExtras(intent);
if (getIntent().hasExtra("initTabByPush")) {
if (getIntent().getIntExtra("initTabByPush", 0) == CHATS) {
doctorCircleFragment.onNewIntentRefresh();
}
setTabByExtra();
}
}
其中,doctorCircleFragment就是那個空指針的罪魁禍首,它會在Activity的onCreate方法中執行個體化。
下面複現:
1.事故Fragment所在Activity叫做A,現在跳轉到另一個Activity待命,叫做B Activity。
2.切換出去,使用清理軟體清理記憶體。
3.切換回APP,發現螢幕白了一下,顯然Application已經被回收
4.在B Activity中跳轉回A Activity,觸發它的onCreate方法及onNewIntent方法
5.發現事故Fragment的onCreate方法日志顯示,其已經被調用
現在挺匪夷所思的,Fragment的onCreate都執行了,doctorCircleFragment不為空,掉你的方法你報還空指針?
那麼隻能有一種可能,就是調用的方法和onCreate的方法不是一個對象。
加入日志列印Object,果然。
因為回收之後FragmentManager會恢複之前的Fragment,是以在Activity的onCreate方法中直接建立Fragment的做法非常不靠譜,
正确的做法是先find這個Fragment是否存在,然後再決定add。否則new出來的Fragment都沒add到布局上,操作它也沒有什麼卵用。
直接使用Fragment的時候可以find,然而FragmentPagerAdapter已經把去重這件事做了,那我們要怎麼擷取這個Fragment呢?
再看Adapter的代碼:
@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);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
是以我們可以通過這個執行個體化方法來擷取被恢複的Fragment,改進後的代碼如下:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
getIntent().putExtras(intent);
if (getIntent().hasExtra("initTabByPush")) {
if (getIntent().getIntExtra("initTabByPush", 0) == CHATS) {
// 解決回收空指針問題
DoctorCircleFragment f = (DoctorCircleFragment)mAdapter.instantiateItem(viewpager, CHATS);
if (f != null){
if (f.isAdded()){
f.onNewIntentRefresh();
}
}
}
setTabByExtra();
}
}
結論:在Activity中擷取Fragment對象的引用的時候,一定要判斷Fragment是否已經添加,否則容易引起空指針問題。
而FragmentPagerAdapter比較特殊,需要一些小把戲。
Fragment的坑還有比如add的操作是異步的,成功之後Activity無法知道,等等。不在此贅述。