項(xiàng)目踩坑記錄
????????項(xiàng)目使用fragmentation框架茎匠,有個(gè)業(yè)務(wù)場(chǎng)景是通過(guò)異步掃描(耗時(shí)操作)進(jìn)行綁定吁朦,如果60秒超時(shí)則自動(dòng)關(guān)閉該頁(yè)面忍啤,該頁(yè)面是一個(gè)fragment编检,在框架里調(diào)用pop()方法就可以關(guān)閉胎食;在正常情況下是沒(méi)有問(wèn)題的,但是如果在60秒的過(guò)程中手機(jī)自動(dòng)熄屏或者鎖屏允懂、home鍵等操作厕怜,當(dāng)60秒時(shí)間到達(dá),調(diào)用pop()時(shí)就會(huì)出現(xiàn)異常:
FATAL EXCEPTION: main
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1842)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:775)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? at me.yokeyword.fragmentation.FragmentationDelegate.debouncePop(FragmentationDelegate.java:500)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? at me.yokeyword.fragmentation.FragmentationDelegate.back(FragmentationDelegate.java:487)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? at me.yokeyword.fragmentation.SupportFragment.pop(SupportFragment.java:652)
第一反應(yīng)查看 Can not perform this action after onSaveInstanceState這個(gè)問(wèn)題蕾总,通過(guò)查看pop()方法源碼:
SupportFragment類中:
接著看back()方法粥航,跳到FragmentationDelegate類中的方法:
注意到紅框中的方法,點(diǎn)過(guò)去
在FragmentManager類中
這是一個(gè)抽象類生百,那在哪里有它的實(shí)現(xiàn)呢递雀,往下翻
終于在這個(gè)實(shí)現(xiàn)類中找到了這個(gè)方法:
原來(lái)是這里拋出了異常,那為什么會(huì)有異常呢蚀浆,從這句異常的提示中我們注意到了這個(gè)方法onSaveInstanceState();原來(lái)手機(jī)自動(dòng)熄屏或者鎖屏缀程、home鍵等操作會(huì)觸發(fā)這個(gè)回調(diào),以防應(yīng)用被殺死后能迅速恢復(fù)到之前的狀態(tài)市俊,這個(gè)方法具體的說(shuō)明可以去閱讀Activity中的源碼杠输。那如何避免這個(gè)異常呢?網(wǎng)上對(duì)于這個(gè)異常的處理有很多秕衙,可參考http://blog.csdn.net/EdisonChang/article/details/49873669
大多是在activity中對(duì)onBackPressed()方法的處理蠢甲,或者直接重寫onSaveInstanceState(),這些方法大多粗暴据忘,要么不能存儲(chǔ)狀態(tài)鹦牛,要么不能在farament中使用搞糕。
我們的項(xiàng)目使用的是單一Activity加多Fragment這種架構(gòu)(現(xiàn)在發(fā)現(xiàn)有很多缺陷),一開始在onSaveInstanceState()方法中嘗試用反射的方法去更改mStateSaved的狀態(tài)為false來(lái)防止異常的拋出曼追,但是發(fā)現(xiàn)在pop()之前會(huì)調(diào)用saveAllState()和dispatchStop()窍仰,這些方法中又將mStateSaved重置為true,換個(gè)思路來(lái)想礼殊,既然我們要解決的pop()時(shí)的問(wèn)題驹吮,那么可以重寫pop(),在調(diào)用父類方法前對(duì)mStateSaved進(jìn)行賦值晶伦,從而避免異常的拋出碟狞,而不需要去考慮什么時(shí)候執(zhí)行了onSaveInstanceState()方法;
@Override
public void pop() {
if(!isSupportVisible()){
invokeFragmentManagerNoteStateNotSaved();
? }
super.pop();
}
private MethodnoteStateNotSavedMethod;
private ObjectfragmentMgr;
private String[]activityClassName = {"Activity", "FragmentActivity"};
public void invokeFragmentManagerNoteStateNotSaved() {
//java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
? if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return;
? }
try {
if (noteStateNotSavedMethod !=null &&fragmentMgr !=null) {
noteStateNotSavedMethod.invoke(fragmentMgr);
return;
? ? ? }
Class cls =_mActivity. getClass();
? ? ? do {
cls = cls.getSuperclass();
? ? ? }while (!(activityClassName[0].equals(cls.getSimpleName())
||activityClassName[1].equals(cls.getSimpleName())));
? ? ? Field fragmentMgrField = prepareField(cls, "mFragments");
? ? ? if (fragmentMgrField !=null) {
fragmentMgr = fragmentMgrField.get(getActivity());
? ? ? ? noteStateNotSavedMethod = getDeclaredMethod(fragmentMgr, "noteStateNotSaved");
? ? ? ? if (noteStateNotSavedMethod !=null) {
noteStateNotSavedMethod.invoke(fragmentMgr);
? ? ? ? }
}
}catch (Exception ex) {
}
}
private FieldprepareField(Class c, String fieldName)throws NoSuchFieldException {
while (c !=null) {
try {
Field f = c.getDeclaredField(fieldName);
? ? ? ? f.setAccessible(true);
? ? ? ? return f;
? ? ? }finally {
c = c.getSuperclass();
? ? ? }
}
throw new NoSuchFieldException();
}
private MethodgetDeclaredMethod(Object object, String methodName, Class... parameterTypes) {
Method method =null;
? for (Class clazz = object.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
method = clazz.getDeclaredMethod(methodName, parameterTypes);
? ? ? ? return method;
? ? ? }catch (Exception e) {
}
}
return null;
}
通過(guò)fragmentation中isSupportVisible()方法可以判斷出是否是不可見狀態(tài)婚陪,如果是的話調(diào)用反射方法族沃,當(dāng)然如果簡(jiǎn)單粗暴一點(diǎn)可以連isSupportVisible()都不判斷,畢竟在屏幕旋轉(zhuǎn)時(shí)這個(gè)方法是不會(huì)觸發(fā)的泌参,而會(huì)調(diào)用onSaveInstanceState()脆淹,引起異常,我們項(xiàng)目中是禁止屏幕旋轉(zhuǎn)的沽一,所以不考慮這種情況盖溺。
對(duì)于反射大致解釋一下,通過(guò)反射FragmentActivity類铣缠,拿到“mFragments”這個(gè)變量咐柜,這個(gè)變量為FragmentController類型,再反射FragmentController類中的noteStateNotSaved方法攘残,
mHost.mFragmentManager就是FragmentManagerImpl拙友,
從而將mStateSaved置為false
現(xiàn)在就可以從容的在熄屏,home狀態(tài)下pop()啦歼郭。