title: Android開發(fā)遇到的異常整理
date: 2019-12-26 11:32:07
tags:
bolg: wwww.gitkyne.com
前言
記錄在開發(fā)過程中遇到的不好找到問題的崩潰異常。
目錄

目錄結(jié)構(gòu)
IllegalArgumentException
java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
at com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed(RequestManagerRetriever.java:134)
at com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:102)
at com.bumptech.glide.Glide.with(Glide.java:653)
場景
當(dāng)你的Activity重新創(chuàng)建并且Glide中的context是舊的時(shí)候,最容易出現(xiàn)。
換言之,context已經(jīng)不在,但是異步處理剛回調(diào)到主線程更新UI,便會(huì)報(bào)異常
解決
問題發(fā)生在當(dāng)前組件的上下文對象(Context)已經(jīng)不存在,即圍繞context做處理
-
方案一
使用控件的context,比如adapter中viewholder.imag.getContext() -
方案二
getApplicationContext() 替代,
然后在onDestroy() 中取消異步請求,避免多余的資源消耗Glide.with(getApplicationContext()).pauseRequests(); -
方案三
加載前做判斷if (ContextUtils.isActivityRunning(xxActivity.this)) {}/** * 判斷正在運(yùn)行的Activity * @param context * @return boolean */ public static boolean isActivityRunning(Context context) { if (context == null) { return false; } if (context instanceof Activity) { return !((Activity) context).isFinishing(); } else if (context instanceof ContextThemeWrapper) { Context baseContext = ((ContextThemeWrapper) context).getBaseContext(); if (baseContext != null) { if (baseContext instanceof Activity) { return !((Activity) baseContext).isFinishing(); } } } return false; }
IllegalStateException
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2080)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2106)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:683)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:637)
...
場景
該異常發(fā)生FragmentManager的commit方法是在Activity的onSaveInstanceState()之后調(diào)用時(shí)發(fā)生。(在commit之前進(jìn)行了異步請求)
原因是onSaveInstanceState()是在onDestroy()前調(diào)用來保存數(shù)據(jù)的,之后便不能再commit,故出錯(cuò)。
解決
commit()替換為commitAllowingStateLoss()
IndexOutOfBoundsException(Inconsistency detected)
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{2064e5c6 position=2 id=-1, oldPos=2, pLpos:-1 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4505)
at android.support.v7.widget.RecyclerView Recycler.getViewForPosition(RecyclerView.java:4636)
at android.support.v7.widget.RecyclerView Recycler.getViewForPosition(RecyclerView.java:4617)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1994)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1390)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:574)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:2979)
...
場景
該問題算是RecyclerView的錯(cuò)誤。對adapter傳入前的List先移除一條數(shù)據(jù),然后又添加數(shù)據(jù),之后再notify,就會(huì)報(bào)錯(cuò)。notify前,adapter內(nèi)部的數(shù)據(jù)還是list移除數(shù)據(jù)前的List,內(nèi)外數(shù)據(jù)不一致導(dǎo)致。
即adapter內(nèi)外數(shù)據(jù)不一致,從而報(bào)錯(cuò)。
解決
-
方案一
自己寫一個(gè)繼承LinearLayoutManager的包裝類,在onLayoutChildren()方法里try-catch捕獲該異常。@Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { super.onLayoutChildren(recycler, state); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } } -
方案二
在進(jìn)行數(shù)據(jù)移除和數(shù)據(jù)增加時(shí),務(wù)必要保證RecyclerView的Adapter中的數(shù)據(jù)集和移除/添加等操作后的數(shù)據(jù)集保持一致!
notifyItemRangeRemoved()
notifyItemRangeInserted()
notifyItemRangeChanged()
使用這些方法之前先處理List數(shù)據(jù),保證數(shù)據(jù)一致每一次對外部數(shù)據(jù)集做改動(dòng)時(shí),都需要緊接著主動(dòng)對外部數(shù)據(jù)集和內(nèi)部數(shù)據(jù)集做一次同步操作
-
方案三
下滑的同時(shí)到adapter更新數(shù)據(jù)完畢,讓RecyclerView暫時(shí)禁止滑動(dòng)。
PS:
不要在列表滑動(dòng)的時(shí)候去更新你的數(shù)據(jù)源
IllegalArgumentException
java.lang.IllegalArgumentException: pointerIndex out of range pointerIndex=-1 pointerCount=1
at android.view.MotionEvent.nativeGetAxisValue(MotionEvent.java)
at android.view.MotionEvent.getX(MotionEvent.java:2216)
at android.support.v4.view.ViewPager.onInterceptTouchEvent(ViewPager.java:2072)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2582)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3041)
....
場景
原因不詳,ViewPager手勢縮放/翻頁時(shí)的錯(cuò)誤。
解決
- 簡單有效的方法,try-catch異常發(fā)生的地方。即繼承ViewPager重寫onTouchEvent() 和onInterceptTouchEvent() 兩個(gè)方法
public class ViewPagerFixed extends android.support.v4.view.ViewPager {
public ViewPagerFixed(Context context) {
super(context);
}
public ViewPagerFixed(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
}