国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Android實際開發(fā)bug大總結(jié)

peixn / 4292人閱讀

摘要:換句話說,環(huán)境或應(yīng)用程序沒有處于請求操作的適當(dāng)狀態(tài)。項目中異常分析引發(fā)崩潰日志的流程分析解決辦法常見的出現(xiàn)場景狀態(tài)異常非法線程操作。導(dǎo)致的方法出來顯示消息位于該消息之后,遲遲沒有執(zhí)行。這時候,的超時檢測結(jié)束,刪除了服務(wù)中的記錄。

目錄介紹

1.1 java.lang.UnsatisfiedLinkError找不到so庫異常

1.2 java.lang.IllegalStateException非法狀態(tài)異常

1.3 android.content.res.Resources$NotFoundException

1.4 java.lang.IllegalArgumentException參數(shù)不匹配異常

1.5 IllegalStateException:Can"t compress a recycled bitmap

1.6 java.lang.NullPointerException空指針異常

1.7 android.view.WindowManager$BadTokenException異常

1.8 java.lang.ClassCastException類轉(zhuǎn)化異常

1.9 Toast運行在子線程問題,handler問題

2.1 java.lang.ClassNotFoundException類找不到異常

2.2 java.util.concurrent.TimeoutException連接超時崩潰

2.3 java.lang.NumberFormatException格式轉(zhuǎn)化錯誤

2.4 java.lang.IllegalStateException: Fragment not attached to Activity

2.5 ArrayIndexOutOfBoundsException 角標(biāo)越界異常

2.6 IllegalAccessException 方法中構(gòu)造方法權(quán)限異常

2.7 android.view.WindowManager$BadTokenException,dialog彈窗異常

2.8 java.lang.NoClassDefFoundError 找不到類異常

2.9 Android出現(xiàn):Your project path contains non-ASCII characters.

3.1 OnErrorNotImplementedException【 Can"t create handler inside thread that has not called Looper.prepare()】

3.2 adb.exe,start-server" failed -- run manually if necessary

3.3 java.lang.IllegalStateException: ExpectedBEGIN_OBJECT but was STRING at line 1 column 1 path $

3.4 android.content.ActivityNotFoundException: No Activity found to handle Intent

3.5 Package manager has died導(dǎo)致崩潰

3.6 IllegalArgumentException View添加窗口錯誤

3.7 IllegalStateException: Not allowed to start service Intent異常崩潰

3.8 java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState

3.9 在Fragment中通過getActivity找不到上下文,報null導(dǎo)致空指針異常

4.1 IllegalArgumentException導(dǎo)致崩潰【url地址傳入非法參數(shù),轉(zhuǎn)義字符】

4.2 ClassNotFoundException: Didn"t find class "" on path: /data/app/*錯誤

4.3 NoClassDefFoundError異常【該異常表示找不到類定義】

4.4 公司之前項目使用客服udesk,sdk更新后初始化導(dǎo)致崩潰問題

4.5 java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception

4.6 java.util.concurrent.ExecutionException: com.android.ide.common.process.ProcessException

4.7 00768556 /vendor/lib/libllvm-glnext.so [armeabi-v8]無法加載so庫導(dǎo)致崩潰

4.8 Only the original thread that created a view hierarchy can touch its views

4.9 NoSuchMethodException android.support.v4.app.Fragment$InstantiationException

好消息

博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識點,Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時開發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長期更新維護(hù)并且修正,持續(xù)完善……開源的文件是markdown格式的!同時也開源了生活博客,從12年起,積累共計47篇[近20萬字],轉(zhuǎn)載請注明出處,謝謝!

鏈接地址:https://github.com/yangchong2...

如果覺得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!

1.1 java.lang.UnsatisfiedLinkError

A.詳細(xì)崩潰日志信息

# main(1)
java.lang.UnsatisfiedLinkError
dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.paidian.hwmc-1/base.apk", dex file "/data/app/com.paidian.hwmc-1/base.apk"],nativeLibraryDirectories=[/data/app/com.paidian.hwmc-1/lib/arm64, /data/app/com.paidian.hwmc-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]] couldn"t find "libijkffmpeg.so"

B.查看崩潰類信息

這個異常類的大意是:如果Java虛擬機找不到聲明為本機的方法的適當(dāng)本機語言定義,則引發(fā)。

public class UnsatisfiedLinkError extends LinkageError {
    private static final long serialVersionUID = -4019343241616879428L;

    public UnsatisfiedLinkError() {
        super();
    }

    public UnsatisfiedLinkError(String s) {
        super(s);
    }
}

C.項目中異常分析

根據(jù)實際項目可知,當(dāng)準(zhǔn)備播放視頻時,找不到libijkffmpeg.so這個庫,導(dǎo)致直接崩潰。

D.引發(fā)崩潰日志的流程分析

F.解決辦法

報這個錯誤通常是so庫加載失敗,或者找不到準(zhǔn)備執(zhí)行的JNI方法:

1.建議檢查so在安裝的過程中是否丟失,沒有放入指定的目錄下;

2.調(diào)用loadLibrary時檢查是否調(diào)用了正確的so文件名,并對其進(jìn)行捕獲,進(jìn)行相應(yīng)的處理,防止程序發(fā)生崩潰;

3.檢查下so的架構(gòu)是否跟設(shè)備架構(gòu)一至(如在64-bit架構(gòu)下調(diào)用32-bit的so)。

代碼展示

ndk {
    //根據(jù)需要 自行選擇添加的對應(yīng)cpu類型的.so庫。
    //abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "mips"
    abiFilters "armeabi-v7a"
}

dependencies {
    compile fileTree(dir: "libs", include: ["*.jar"])
    //這兩個是必須要加的,其它的可供選擇
    compile "tv.danmaku.ijk.media:ijkplayer-java:0.8.4"
    compile "tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4"
    //其他庫文件
    //compile "tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8"
    //compile "tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8"
    //compile "tv.danmaku.ijk.media:ijkplayer-x86:0.8.8"
    //compile "tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8"
}

G.知識延申

Android 應(yīng)用開發(fā)者應(yīng)該對 UnsatisfiedLinkError 這種類型的錯誤比較熟悉了,這個問題一直困擾著廣大的開發(fā)者,那么有沒有想過有可能你什么都沒做錯,也會出現(xiàn)這個問題呢?

我們在 Android 應(yīng)用開發(fā)測試過程中曾經(jīng)碰到過這樣的案例,apk 在某機型上安裝完成之后運行即崩潰,報錯 UnsatisfiedLinkError。

java.lang.UnsatisfiedLinkError: Couldn’t load mobsec from loader dalvik.system.PathClassLoader.....findLibrary returned null

首先懷疑是在 apk 中相應(yīng)的 libsabi 目錄下沒有放置 libmobsec.so,然而檢查發(fā)現(xiàn)這個 so 在所有的 libsabi 下都有放置過,繼續(xù)排查;

然后的想法是放置的 so 不是對應(yīng) abi 的,比如由于粗心在 armeabi 目錄下放置了 x86 指令集的 so,導(dǎo)致在 armeabi 指令集手機上加載出錯,這個也被排除掉;

就在沒有頭緒的時候,想到 System.loadLibrary 函數(shù)加載 so 時,系統(tǒng)是從指定的路徑下加載的,那么這個路徑下 so 是否存在呢?

我們知道應(yīng)用的私有 Native library 目錄 /data/data/packagename/lib 是一個符號鏈接,鏈接到 /data/app-lib/ 目錄,System.loadLibrary 是到這個目錄去嘗試加載 so 的。

adb shell 到這個路徑下,使用命令 ls 查看,果然這個 libmobsec.so 是不存在的。那么是什么原因?qū)е碌哪兀?/p>

分析 Android 系統(tǒng)源碼的實現(xiàn),發(fā)現(xiàn) /data/app-lib/ 這個目錄下的 so ,是在系統(tǒng)安裝 apk 時從 apk 的 lib 目錄下去抽取的。

1.2 java.lang.IllegalStateException非法狀態(tài)異常

A.詳細(xì)崩潰日志信息

onSaveInstanceState方法是在該Activity即將被銷毀前調(diào)用,來保存Activity數(shù)據(jù)的,如果在保存玩狀態(tài)后

再給它添加Fragment就會出錯。

IllegalStateException: Can not perform this action after onSaveInstanceState:

B.查看崩潰類信息

在非法或不適當(dāng)?shù)臅r間調(diào)用方法的信號。換句話說,Java環(huán)境或Java應(yīng)用程序沒有處于請求操作的適當(dāng)狀態(tài)。

public class IllegalStateException extends RuntimeException {
    public IllegalStateException() {
        super();
    }

    public IllegalStateException(String s) {
        super(s);
    }

    public IllegalStateException(String message, Throwable cause) {
        super(message, cause);
    }

    public IllegalStateException(Throwable cause) {
        super(cause);
    }

    static final long serialVersionUID = -1848914673093119416L;
}

C.項目中異常分析

分析

D.引發(fā)崩潰日志的流程分析

F.解決辦法

解決辦法就是把commit()方法替換成 commitAllowingStateLoss()

G.其他延申

錯誤類型大致為以下幾種:

java.lang.IllegalStateException:Can"t change tag of fragment d{e183845 #0 d{e183845}}: was d{e183845} now d{e183845 #0 d{e183845}}
java.lang.IllegalStateException:Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 37 path $.data

第一種:我在顯示fragment的代碼中使用了:fragment.show(getSupportFragmentManager, fragment.toString());而這里是因為兩次toString()結(jié)果不同,導(dǎo)致不同的tag指向的是同一個fragment。獲取fragment的tag的正確方法應(yīng)該是使用其提供的fragment.getTag()方法。

第二種:該異常是由于服務(wù)器錯誤返回的JSON字符串和服務(wù)器正常下時返回的JSON字符串結(jié)構(gòu)不同,導(dǎo)致利用Gson解析的時候報了一個異常:本該去解析集合卻強制去解析對象所致.解決辦法:在使用Gson解析JSON時try cash一下,不報錯按照正常邏輯繼續(xù)解析,報異常則處理為請求失敗邏輯即可.

1.3 android.content.res.Resources$NotFoundException

A.詳細(xì)崩潰日志信息

Android資源不是可繪制的(顏色或路徑)

Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f040151 a=2}
android.view.LayoutInflater.createView(LayoutInflater.java:620)

B.查看崩潰類信息

當(dāng)找不到請求的資源時,資源API將引發(fā)此異常。

public static class NotFoundException extends RuntimeException {
    public NotFoundException() {
    }

    public NotFoundException(String name) {
        super(name);
    }

    public NotFoundException(String name, Exception cause) {
        super(name, cause);
    }
}

C.項目中異常分析

由于將圖片資源拷貝到了drawable-land-xhdpi目錄下,本來應(yīng)該拷貝到drawable-xhdpi目錄下。

D.引發(fā)崩潰日志的流程分析

F.解決辦法

1.引用的資源ID 是否能匹配到R.java文件中定義的資源;

2.是否因為緩存等原因?qū)е戮幾gAPK時未把資源文件打包進(jìn)去,可以把APK反編譯檢查下;

3.是否使用了一個錯誤的類型來引用了某個資源或者配置資源時存在錯誤;

4.是否將Int等整型變量作為了參數(shù)傳給了View.setText調(diào)用,這種情況下該整型變量將被認(rèn)為是一個資源ID號去資源列表中查找對應(yīng)的資源,導(dǎo)致找不到對應(yīng)資源錯誤;解決方法是做類型轉(zhuǎn)換View.setText(String.valueOf(Int id))。

1.4 java.lang.IllegalArgumentException參數(shù)不匹配異常

A.詳細(xì)崩潰日志信息

B.查看崩潰類信息

參數(shù)不匹配異常,通常由于傳遞了不正確的參數(shù)導(dǎo)致。

public class IllegalArgumentException extends RuntimeException {
    public IllegalArgumentException() {
        super();
    }

    public IllegalArgumentException(String s) {
        super(s);
    }

    public IllegalArgumentException(String message, Throwable cause) {
        super(message, cause);
    }


    public IllegalArgumentException(Throwable cause) {
        super(cause);
    }

    private static final long serialVersionUID = -5365630128856068164L;
}

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

F.解決辦法

G.常見的出現(xiàn)場景

Activity、Service狀態(tài)異常;

非法URL;

UI線程操作。

Fragment中嵌套了子Fragment,F(xiàn)ragment被銷毀,而內(nèi)部Fragment未被銷毀,所以導(dǎo)致再次加載時重復(fù),在onDestroyView() 中將內(nèi)部Fragment銷毀即可

在請求網(wǎng)絡(luò)的回調(diào)中使用了glide.into(view),view已經(jīng)被銷毀會導(dǎo)致該錯誤

1.5 IllegalStateException:Can"t compress a recycled bitmap

A.詳細(xì)崩潰日志信息

無法壓縮回收位圖

Can"t compress a recycled bitmap
com.paidian.hwmc.utils.i.a(FileUtils.java:75)

B.查看崩潰類信息

如果位圖已被回收,則希望拋出異常的方法將調(diào)用此值。知道了崩潰的具體位置,就該分析具體的原因呢!

public boolean compress(CompressFormat format, int quality, OutputStream stream) {
    checkRecycled("Can"t compress a recycled bitmap");
    //省略代碼
    return result;
}

//如果位圖已被回收,則希望拋出異常的方法將調(diào)用此值。
private void checkRecycled(String errorMessage) {
    if (mRecycled) {
        throw new IllegalStateException(errorMessage);
    }
}

C.項目中異常分析

使用了已經(jīng)被釋放過內(nèi)存的對象。對于Bitmap:Bitmap bitmap=一個bitmap對象。使用過程中調(diào)用bitmap.recycle(),之后再使用bitmap就會報錯。

D.引發(fā)崩潰日志的流程分析

bitmap.recycle()解釋如下所示,釋放與此位圖關(guān)聯(lián)的本機對象,并清除對像素數(shù)據(jù)的引用。這將不會同步釋放像素數(shù)據(jù);它只允許在沒有其他引用的情況下對其進(jìn)行垃圾收集。位圖被標(biāo)記為“死”,這意味著如果調(diào)用getPixels()或setPixels(),它將拋出異常,而不會繪制任何內(nèi)容。此操作不能反轉(zhuǎn),因此只有在確定沒有進(jìn)一步使用位圖的情況下才應(yīng)調(diào)用該操作。這是一個高級調(diào)用,通常不需要調(diào)用,因為當(dāng)沒有對此位圖的引用時,普通GC進(jìn)程將釋放此內(nèi)存。

Free the native object associated with this bitmap, and clear the reference to the pixel data

F.解決辦法

第一種:在使用bitmap前增加判斷,if (mBitmap.isRecycled()) return null;

1.6 java.lang.NullPointerException空指針異常

A.詳細(xì)崩潰日志信息

Please call the AutoSizeConfig#init() first
com.paidian.hwmc.base.BaseApplication.initAutoSizeConfig(BaseApplication.java:386)

B.查看崩潰類信息

空指針異常,也是十分常見的一個異常

public class NullPointerException extends RuntimeException {
    private static final long serialVersionUID = 5162710183389028792L;
    public NullPointerException() {
        super();
    }
    public NullPointerException(String s) {
        super(s);
    }
}

C.項目中異常分析

空指針發(fā)生場景較多,是指某一個對象報null,這個使用去使用它的話就i會報該異常。

D.引發(fā)崩潰日志的流程分析

導(dǎo)致出現(xiàn)空指針的原因: 必須滿足兩個條件才會發(fā)生空指針:引用變量指向了空,并且調(diào)用了這個引用的方法

空指針問題解決思路:

查看Log信息看第一行導(dǎo)致空指針發(fā)生的代碼,直接雙擊打開報空指針的類

查看該行代碼中有幾處調(diào)用了方法,則有幾個對象可能是空的,找出哪個對象是空的

查看這些對方在哪里賦值了

如果沒賦值,則給她賦值,問題解決

如果有地方賦值了,則看這個方法有沒有被調(diào)用(Ctrl + Shift + G)

如果沒有調(diào)用(可能沒調(diào)用或可能調(diào)用時機太晚),在使用她前先調(diào)用賦值,問題解決

如果有調(diào)用,則看是不是有其它地方又給她賦值為null了,如果沒有設(shè)置為null,則要看賦值的變量和我們使用時的變量是否是同一個變量。

F.解決辦法

空指針最為常見,也最容易規(guī)避,使用的時候一定要進(jìn)行null check,采取不信任原則:

1.方法形參要判空后才使用;

2.全局變量容易被系統(tǒng)回收或者更改,使用全局變量前建議判空;

3.第三方接口的調(diào)用,對返回值進(jìn)行判空。

4.請注意線程安全

1.7 android.view.WindowManager$BadTokenException異常,Toast報錯Unable to add window

A.詳細(xì)崩潰日志信息

報錯日志,是不是有點眼熟呀?更多可以看我的開源項目:https://github.com/yangchong211

android.view.WindowManager$BadTokenException
    Unable to add window -- token android.os.BinderProxy@7f652b2 is not valid; is your activity running?

B.查看崩潰類信息

查詢報錯日志是從哪里來的

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

這個異常發(fā)生在Toast顯示的時候,原因是因為token失效。通常情況下,一般是不會出現(xiàn)這種異常。但是由于在某些情況下, Android進(jìn)程某個UI線程的某個消息阻塞。導(dǎo)致 TN 的 show 方法 post 出來 0 (顯示) 消息位于該消息之后,遲遲沒有執(zhí)行。這時候,NotificationManager 的超時檢測結(jié)束,刪除了 WMS 服務(wù)中的 token 記錄。刪除 token 發(fā)生在 Android 進(jìn)程 show 方法之前。這就導(dǎo)致了上面的異常。

測試代碼。模擬一下異常的發(fā)生場景,其實很容易,只需要這樣做就可以出現(xiàn)上面這個問題

 Toast.makeText(this,"瀟湘劍雨-yc",Toast.LENGTH_SHORT).show();
    try {
        Thread.sleep(20000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

F.解決辦法

目前見過好幾種,思考一下那種比較好……

第一種,既然是報is your activity running,那可以不可以在吐司之前先判斷一下activity是否running呢?

第二種,拋出異常增加try-catch,代碼如下所示,最后仍然無法解決問題

按照源碼分析,異常是發(fā)生在下一個UI線程消息中,因此在上一個ui線程消息中加入try-catch是沒有意義的。而且用到吐司地方這么多,這樣做也不方便啦!

第三種,那就是自定義類似吐司Toast的view控件。個人建議除非要求非常高,不然不要這樣做。畢竟發(fā)生這種異常還是比較少見的

G.哪些情況會發(fā)生該問題?

UI 線程執(zhí)行了一條非常耗時的操作,比如加載圖片等等,就類似上面用 sleep 模擬情況

進(jìn)程退后臺或者息屏了,系統(tǒng)為了減少電量或者某種原因,分配給進(jìn)程的cpu時間減少,導(dǎo)致進(jìn)程內(nèi)的指令并不能被及時執(zhí)行,這樣一樣會導(dǎo)致進(jìn)程看起來”卡頓”的現(xiàn)象

當(dāng)TN拋出消息的時候,前面有大量的 UI 線程消息等待執(zhí)行,而每個 UI 線程消息雖然并不卡頓,但是總和如果超過了 NotificationManager 的超時時間,還是會出現(xiàn)問題

1.8 java.lang.ClassCastException類轉(zhuǎn)化異常

A.詳細(xì)崩潰日志信息

android.widget.FrameLayout cannot be cast to android.widget.RelativeLayout
com.paidian.hwmc.goods.activity.GoodsDetailsActivity.initView(GoodsDetailsActivity.java:712)

B.查看崩潰類信息

拋出以指示代碼試圖將對象強制轉(zhuǎn)換為它不是實例的子類。

public class ClassCastException extends RuntimeException {
    private static final long serialVersionUID = -9223365651070458532L;


    public ClassCastException() {
        super();
    }

    public ClassCastException(String s) {
        super(s);
    }
}

C.項目中異常分析

該異常表示類型轉(zhuǎn)換異常,通常是因為一個類對象轉(zhuǎn)換為其他不兼容類對象拋出的異常,檢查你要轉(zhuǎn)換的類對象類型。

D.引發(fā)崩潰日志的流程分析

F.解決辦法

一般在強制類型轉(zhuǎn)換時出現(xiàn),例如如果A向B轉(zhuǎn)換,而A不是B的父類時,將產(chǎn)生java.lang.ClassCastException異常。一般建議做這時要使用instanceof做一下類型判斷,再做轉(zhuǎn)換。

該案例中,需要把FrameLayout更改成RelativeLayout就可以呢

1.9 Toast運行在子線程問題,handler問題

A.詳細(xì)崩潰日志信息

先來看看問題代碼,會出現(xiàn)什么問題呢?

new Thread(new Runnable() {
    @Override
    public void run() {
        ToastUtils.showRoundRectToast("瀟湘劍雨-楊充");
    }
}).start();

報錯日志如下所示:

然后找找報錯日志從哪里來的

![image]()

子線程中吐司的正確做法,代碼如下所示

new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare();
        ToastUtils.showRoundRectToast("瀟湘劍雨-楊充");
        Looper.loop();
    }
}).start();

得出的結(jié)論

Toast也可以在子線程執(zhí)行,不過需要手動提供Looper環(huán)境的。

Toast在調(diào)用show方法顯示的時候,內(nèi)部實現(xiàn)是通過Handler執(zhí)行的,因此自然是不阻塞Binder線程,另外,如果addView的線程不是Loop線程,執(zhí)行完就結(jié)束了,當(dāng)然就沒機會執(zhí)行后續(xù)的請求,這個是由Hanlder的構(gòu)造函數(shù)保證的。可以看看handler的構(gòu)造函數(shù),如果Looper==null就會報錯,而Toast對象在實例化的時候,也會為自己實例化一個Hanlder,這就是為什么說“一定要在主線程”,其實準(zhǔn)確的說應(yīng)該是 “一定要在Looper非空的線程”。

Handler的構(gòu)造函數(shù)如下所示:

2.1 java.lang.ClassNotFoundException類找不到異常

A.詳細(xì)崩潰日志信息

Didn"t find class "om.scwang.smartrefresh.layout.SmartRefreshLayout" on path: DexPathList[[zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/base.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_dependencies_apk.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_slice_0_apk.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_slice_1_apk.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_s
com.paidian.hwmc.goods.activity.GoodsDetailsActivity.onCreate(GoodsDetailsActivity.java:209)

B.查看崩潰類信息

當(dāng)應(yīng)用程序嘗試使用字符串名稱加載類時引發(fā):但無法找到具有指定名稱的類的定義。從1.4版開始,已對此異常進(jìn)行了修改,以符合通用的異常鏈接機制。在構(gòu)建時提供并通過{@link#getException()}方法訪問的“在加載類時引發(fā)的可選異常”現(xiàn)在稱為原因,并且可以通過{@link Throwable#getCace()}方法以及前面提到的“遺留方法”進(jìn)行訪問。

public class ClassNotFoundException extends ReflectiveOperationException {
    private static final long serialVersionUID = 9176873029745254542L;
    private Throwable ex;
    public ClassNotFoundException() {
        super((Throwable)null);  // Disallow initCause
    }
    public ClassNotFoundException(String s) {
        super(s, null);  //  Disallow initCause
    }
    public ClassNotFoundException(String s, Throwable ex) {
        super(s, null);  //  Disallow initCause
        this.ex = ex;
    }
    public Throwable getException() {
        return ex;
    }
    public Throwable getCause() {
        return ex;
    }
}

C.項目中異常分析

該異常表示在路徑下,找不到指定類,通常是因為構(gòu)建路徑問題導(dǎo)致的。

D.引發(fā)崩潰日志的流程分析

F.解決辦法

類名是以字符串形式標(biāo)識的,可信度比較低,在調(diào)用Class.forName(""),Class.findSystemClass(""),Class.loadClass("")等方法時,找不到類名時將會報錯。如果找不到的Class是系統(tǒng)Class,那么可能是系統(tǒng)版本兼容,廠家Rom兼容的問題,找到對應(yīng)的設(shè)備嘗試重現(xiàn),解決方法可以考慮更換Api,或用自己實現(xiàn)的Class替代。

如果找不到的Class是應(yīng)用自由Class(含第三方SDK的Class),可以通過反編譯工具查看對應(yīng)apk中是否真的缺少該Class,再進(jìn)行定位,這種往往發(fā)生在:

1.要找的Class被混淆了,存在但名字變了;

2.要找的Class未被打入Dex,確實不存在,可能是因為自己的疏忽,或編譯環(huán)境的沖突;

3.要找的Class確實存在,但你的Classlorder找不到這個Class,往往因為這個Classloder是你自實現(xiàn)的(插件化應(yīng)用中常見)。

G.其他延申

2.2 java.util.concurrent.TimeoutException連接超時崩潰

A.詳細(xì)崩潰日志信息

java.util.concurrent.TimeoutException: android.view.ThreadedRenderer.finalize() timed out after 10 seconds
at android.view.ThreadedRenderer.nDeleteProxy(Native Method)
at android.view.ThreadedRenderer.finalize(ThreadedRenderer.java:423) 

B.查看崩潰類信息

當(dāng)阻塞操作超時引發(fā)的異常。指定超時的阻塞操作需要一種方法來指示已發(fā)生超時。對于許多此類操作,可以返回指示超時的值;如果不可能或不需要,則應(yīng)聲明并拋出{@code TimeoutException}。

public class TimeoutException extends Exception {
    private static final long serialVersionUID = 1900926677490660714L;
    public TimeoutException() {}
    public TimeoutException(String message) {
        super(message);
    }
}

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

F.解決辦法

一般是系統(tǒng)在gc時,調(diào)用對象的finalize超時導(dǎo)致,解決辦法:

1.檢查分析finalize的實現(xiàn)為什么耗時較高,修復(fù)它;

2.檢查日志查看GC是否過于頻繁,導(dǎo)致超時,減少內(nèi)容開銷,防止內(nèi)存泄露。

G.其他延申

2.3 java.lang.NumberFormatException格式轉(zhuǎn)化錯誤

A.詳細(xì)崩潰日志信息

Exception in thread "main" java.lang.NumberFormatException: For input string: "100 "
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:458)
    at java.lang.Integer.parseInt(Integer.java:499)

B.查看崩潰類信息

引發(fā),以指示應(yīng)用程序試圖將字符串轉(zhuǎn)換為數(shù)字類型之一,但該字符串沒有適當(dāng)?shù)母袷健?/p>

public class NumberFormatException extends IllegalArgumentException {
    static final long serialVersionUID = -2848938806368998894L;

    public NumberFormatException () {
        super();
    }

    public NumberFormatException (String s) {
        super (s);
    }

    static NumberFormatException forInputString(String s) {
        return new NumberFormatException("For input string: "" + s + """);
    }
}

C.項目中異常分析

錯誤關(guān)鍵字 java.lang.NumberFormatException 這句話明確告訴了我們是數(shù)字格式異常,接著后面有 For input string: "100 " 提示,這就告訴我們,當(dāng)前想把 "100 " 轉(zhuǎn)換成數(shù)字類型時出錯了,這樣就很確切了。

D.引發(fā)崩潰日志的流程分析

F.解決辦法

解決辦法很簡單,改成 Integer.parseInt(str.trim()),注意將字符串轉(zhuǎn)化成整數(shù)數(shù)據(jù)類型時,注意需要trim一下。

G.其他延申

2.4 java.lang.IllegalStateException: Fragment not attached to Activity

A.詳細(xì)崩潰日志信息

java.lang.IllegalStateException: Fragment not attached to Activity

B.查看崩潰類信息

C.項目中異常分析

出現(xiàn)該異常,是因為Fragment的還沒有Attach到Activity時,調(diào)用了如getResource()等,需要上下文Content的函數(shù)。

出現(xiàn)該異常,是因為Fragment還沒有Attach到Activity時,調(diào)用了如getResource()等,需要上下文Context的函數(shù)。解決方法,就是等將調(diào)用的代碼寫在OnStart()中。

D.引發(fā)崩潰日志的流程分析

F.解決辦法

將調(diào)用的代碼運行在Fragment Attached的生命周期內(nèi)。

第一種:在調(diào)用需要Context的函數(shù)之前,增加一個判斷isAdded()

if(isAdded()){//isAdded方法是Android系統(tǒng)提供的,只有在Fragment被添加到所屬的Activity后才返回true
    activity.getResourses().getString(...);
}

第二種:如下所示

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    activity = (MainActivity) context;
}

@Override
public void onDetach() {
    super.onDetach();
    if (activity != null) {
        activity = null;
    }
}

G.其他延申

發(fā)生場景:該錯誤經(jīng)常發(fā)生在fragment的線程中執(zhí)行了一個耗時操作,線程在執(zhí)行完畢后會調(diào)用getResources來更新ui。如果在線程操作沒有完成,就調(diào)用getActivity().recreate()重新加載activity或屏幕旋轉(zhuǎn),這時就會出現(xiàn)Fragment not attached to Activity的錯誤

2.5 ArrayIndexOutOfBoundsException 角標(biāo)越界異常

A.詳細(xì)崩潰日志信息

該異常表示數(shù)組越界

java.lang.ArrayIndexOutOfBoundsException: 0
    at com.example.mytest.CityAdapter.setDataNotify(CityAdapter.java:183)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

B.查看崩潰類信息

引發(fā),以指示已使用非法索引訪問數(shù)組。索引不是負(fù)的,就是大于或等于數(shù)組的大小。

public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
    private static final long serialVersionUID = -5116101128118950844L;
    public ArrayIndexOutOfBoundsException() {
        super();
    }
    public ArrayIndexOutOfBoundsException(int index) {
        super("Array index out of range: " + index);
    }
    public ArrayIndexOutOfBoundsException(String s) {
        super(s);
    }
    public ArrayIndexOutOfBoundsException(int sourceLength, int index) {
        super("length=" + sourceLength + "; index=" + index);
    }
    public ArrayIndexOutOfBoundsException(int sourceLength, int offset,
            int count) {
        super("length=" + sourceLength + "; regionStart=" + offset
                + "; regionLength=" + count);
    }
}

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

F.解決辦法

這種情況一般要在數(shù)組循環(huán)前做好length判斷,index超出length上限和下限時都會報錯。舉例如下:一個數(shù)組int test[N],一共有N個元素分別是test[0]~test[N-1],如果調(diào)用test[N],將會報錯。建議讀取時,不要超過數(shù)組的長度(array.length)。

Android中一種常見情形就是上拉刷新中header也會作為listview的第0個位置,如果判斷失誤很容易造成越界。

G.其他延申

2.6 IllegalAccessException 方法中構(gòu)造方法權(quán)限異常

A.詳細(xì)崩潰日志信息

Unable to instantiate application com.pedaily.yc.meblurry.App: java.lang.IllegalAccessException

B.查看崩潰類信息

當(dāng)應(yīng)用程序試圖反射地創(chuàng)建實例(數(shù)組除外)、設(shè)置或獲取字段或調(diào)用方法時,將引發(fā)IllegalAccessException,但當(dāng)前執(zhí)行的方法無法訪問指定的類、字段、方法或構(gòu)造函數(shù)的定義。

public class IllegalAccessException extends ReflectiveOperationException {
    private static final long serialVersionUID = 6616958222490762034L;
    public IllegalAccessException() {
        super();
    }
    public IllegalAccessException(String s) {
        super(s);
    }
}

C.項目中異常分析

錯誤提示是,構(gòu)造方法的權(quán)限不對

D.引發(fā)崩潰日志的流程分析

F.解決辦法

檢查了整個Application,才發(fā)現(xiàn),原來有一個無參數(shù)的構(gòu)造方法,被設(shè)計成private。修改其為public即可。

G.其他延申

android BroadcastReceiver遇到j(luò)ava.lang.IllegalAccessException解決方法,錯誤原因主要是app中其他地方調(diào)用了默認(rèn)的構(gòu)造函數(shù),必須增加默認(rèn)構(gòu)造函數(shù)且訪問權(quán)限為public

2.7 android.view.WindowManager$BadTokenException,dialog彈窗異常

A.詳細(xì)崩潰日志信息

Unable to add window -- token android.os.BinderProxy@9a57804 is not valid; is your activity running?
android.view.ViewRootImpl.setView(ViewRootImpl.java:907)

B.查看崩潰類信息

在WindowManager中可以找到這個異常類,主要發(fā)生在嘗試添加視圖時引發(fā)的

public static class BadTokenException extends RuntimeException {
    public BadTokenException() {
    }

    public BadTokenException(String name) {
        super(name);
    }
}

C.項目中異常分析

該異常表示不能添加窗口,通常是所要依附的view已經(jīng)不存在導(dǎo)致的。

D.引發(fā)崩潰日志的流程分析

F.解決辦法

之前項目中有一個自定義彈窗,偶爾會報這個錯。解決辦法如下代碼所示

主要邏輯是在彈窗show或者dismiss的時候,都增加了邏輯判斷,判斷宿主activity存在。

/**
 * 展示加載窗
 * @param context               上下文
 * @param isCancel              是否可以取消
 */
public static void show(Context context,  boolean isCancel) {
    if(context == null){
        return;
    }
    if (context instanceof Activity) {
        if (((Activity) context).isFinishing()) {
            return;
        }
    }
    if (loadDialog != null && loadDialog.isShowing()) {
        return;
    }
    loadDialog = new LoadLayoutDialog(context, isCancel);
    loadDialog.show();
}

/**
 * 銷毀加載窗
 * @param context               上下文
 */
public static void dismiss(Context context) {
    if(context == null){
        return;
    }
    try {
        if (context instanceof Activity) {
            if (((Activity) context).isFinishing()) {
                loadDialog = null;
                return;
            }
        }
        if (loadDialog != null && loadDialog.isShowing()) {
            Context loadContext = loadDialog.getContext();
            if (loadContext instanceof Activity) {
                if (((Activity) loadContext).isFinishing()) {
                    loadDialog = null;
                    return;
                }
            }
            loadDialog.dismiss();
            loadDialog = null;
        }
    } catch (Exception e) {
        e.printStackTrace();
        loadDialog = null;
    }
}

G.其他延申

Dialog&AlertDialog,Toast,WindowManager不能正確使用時,經(jīng)常會報出該異常,原因比較多,幾個常見的場景如下:

1.上一個頁面沒有destroy的時候,之前的Activity已經(jīng)接收到了廣播。如果此時之前的Activity進(jìn)行UI層面的操作處理,就會造成crash。UI層面的刷新,一定要注意時機,建議使用set_result來代替廣播的形式進(jìn)行刷新操作,避免使用廣播的方式,代碼不直觀且容易出錯。

2.Dialog在Actitivty退出后彈出。在Dialog調(diào)用show方法進(jìn)行顯示時,必須要有一個Activity作為窗口的載體,如果Activity被銷毀,那么導(dǎo)致Dialog的窗口載體找不到。建議在Dialog調(diào)用show方法之前先判斷Activity是否已經(jīng)被銷毀。

3.Service&Application彈出對話框或WindowManager添加view時,沒有設(shè)置window type為TYPE_SYSTEM_ALERT。需要在調(diào)用dialog.show()方法前添加dialog.getWindow().SetType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)。

4.6.0的系統(tǒng)上, (非定制 rom 行為)若沒有給予懸浮窗權(quán)限, 會彈出該問題, 可以通過Settings.canDrawOverlays來判斷是否有該權(quán)限.

5.某些不穩(wěn)定的MIUI系統(tǒng)bug引起的權(quán)限問題,系統(tǒng)把Toast也當(dāng)成了系統(tǒng)級彈窗,android6.0的系統(tǒng)Dialog彈窗需要用戶手動授權(quán),若果app沒有加入SYSTEM_ALERT_WINDOW權(quán)限就會報這個錯。需要加入給app加系統(tǒng)Dialog彈窗權(quán)限,并動態(tài)申請權(quán)限,不滿足第一條會出現(xiàn)沒權(quán)限閃退,不滿足第二條會出現(xiàn)沒有Toast的情況。

H.其他建議

1.不要在非UI線程中使用對話框創(chuàng)建,顯示和取消對話框;

2.盡量少用多帶帶線程,出發(fā)是真正的耗時操作采用線程,線程也不要直接用Java式的匿名線程,除非是那種單純的操作,操作完成不需要做其他事情的。

3.如果是在fragment中發(fā)起異步網(wǎng)絡(luò)的回調(diào)中進(jìn)行dialog的操作,那么在操作之前,需要判斷 isAdd( ),避免fragment被回收了但是還要求dialog去dismiss

4.在Activity onDestroy中對Dialog提前進(jìn)行關(guān)閉

2.8 java.lang.NoClassDefFoundError 找不到類異常

A.詳細(xì)崩潰日志信息

B.查看崩潰類信息

如果Java虛擬機或ClassLoader實例試圖加載類的定義(作為普通方法調(diào)用的一部分或使用新的表達(dá)式創(chuàng)建新實例的一部分),則拋出該類的定義。編譯當(dāng)前執(zhí)行的類時存在搜索類定義,但無法再找到該定義。

public class NoClassDefFoundError extends LinkageError {
    private static final long serialVersionUID = 9095859863287012458L;
    public NoClassDefFoundError() {
        super();
    }
    public NoClassDefFoundError(String s) {
        super(s);
    }
    private NoClassDefFoundError(String detailMessage, Throwable throwable) {
        super(detailMessage, throwable);
    }
}

C.項目中異常分析

問題的主要原因:方法數(shù)超65536限制。由于實際開發(fā)當(dāng)中的需求不斷變更,開源框架越來越多,大多都用第三方SDK,導(dǎo)致方法數(shù)很容易超出65536限制。出現(xiàn)錯誤Java.lang.NoClassDefFoundError

D.引發(fā)崩潰日志的流程分析

這個錯誤是Android應(yīng)用的方法總數(shù)限制造成的。android平臺的Java虛擬機Dalvik在執(zhí)行DEX格式的Java應(yīng)用程序時,使用原生類型short來索引DEX文件中的方法。這意味著單個DEX文件可被引用的方法總數(shù)被限制為65536。通常APK包含一個classes.dex文件,因此Android應(yīng)用的方法總數(shù)不能超過這個數(shù)量,這包括Android框架、類庫和你自己開發(fā)的代碼。而Android 5.0和更高版本使用名為ART的運行時,它原生支持從APK文件加載多個DEX文件。在應(yīng)用安裝時,它會執(zhí)行預(yù)編譯,掃描classes(..N).dex文件然后將其編譯成單個.oat文件用于執(zhí)行. 通熟的講,就是分包。

F.解決辦法

64k解決辦法

G.其他延申

該異常表示找不到類定義,當(dāng)JVM或者ClassLoader實例嘗試裝載該類的定義(這通常是一個方法調(diào)用或者new表達(dá)式創(chuàng)建一個實例過程的一部分)而這個類定義并沒有找時所拋出的錯誤。

[解決方案]:NoClassDefFoundError異常一般出現(xiàn)在編譯環(huán)境和運行環(huán)境不一致的情況下,就是說有可能在編譯過后更改了Classpath或者jar包所以導(dǎo)致在運行的過程中JVM或者ClassLoader無法找到這個類的定義。

1.分dex包編程,如果依賴的dex包刪除了指定的類,執(zhí)行初始化方法時將會報錯;

2.使用第三方SDK或插件化編程時,動態(tài)加載或?qū)嵗愂箦e;

3.系統(tǒng)資源緊張時,當(dāng)大量class需要加載到內(nèi)存的時候,處于競爭關(guān)系,部分calss競爭失敗,導(dǎo)致加載不成功;

4.裝載并初始化一個類時失敗(比如靜態(tài)塊拋 java.lang.ExceptionInInitializerError 異常),然后再次引用此類也會提示NoClassDefFoundErr 錯誤;

5.手機系統(tǒng)版本或硬件設(shè)備不匹配(如ble設(shè)備只支持18以上SDK),程序引用的class在低版本中不存在,導(dǎo)致NoClassDefFoundErr 錯誤。

6.so文件找不到,設(shè)備平臺armeabi-v7a,但是我的so庫是放在armeabi中的,解決方法新建一個armeabi-v7a包,并且把armeabi的文件拷貝過來.

2.9 Android出現(xiàn):Your project path contains non-ASCII characters.

A.詳細(xì)崩潰日志信息

B.查看崩潰類信息

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

F.解決辦法

很好解決啦,就是你的工程項目路徑或者項目名稱包含了中文,修改相關(guān)的名稱就好

G.其他延申

3.1 OnErrorNotImplementedException【 Can"t create handler inside thread that has not called Looper.prepare()】

A.詳細(xì)崩潰日志信息

Can"t create handler inside thread that has not called Looper.prepare()

B.查看崩潰類信息

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

這是因為Handler對象與其調(diào)用者在同一線程中,如果在Handler中設(shè)置了延時操作,則調(diào)用線程也會堵塞。每個Handler對象都會綁定一個Looper對象,每個Looper對象對應(yīng)一個消息隊列(MessageQueue)。如果在創(chuàng)建Handler時不指定與其綁定的Looper對象,系統(tǒng)默認(rèn)會將當(dāng)前線程的Looper綁定到該Handler上。

在主線程中,可以直接使用new Handler()創(chuàng)建Handler對象,其將自動與主線程的Looper對象綁定;在非主線程中直接這樣創(chuàng)建Handler則會報錯,因為Android系統(tǒng)默認(rèn)情況下非主線程中沒有開啟Looper,而Handler對象必須綁定Looper對象。

如果在主線程中創(chuàng)建handler時,系統(tǒng)會自動創(chuàng)建Looper,但是在子線程中創(chuàng)建handler時,是不會自動創(chuàng)建Looper的,此時如果不手動創(chuàng)建Looper,系統(tǒng)就會崩潰

F.解決辦法

不要在子線程中做UI操作,比如更改界面,吐司等等……

方法1:需先在該線程中手動開啟Looper(Looper.prepare()-->Looper.loop()),然后將其綁定到Handler對象上;

final Runnable runnable = new Runnable() {
  @Override
  public void run() {
    //執(zhí)行耗時操作
    try {

      Log.e("bm", "runnable線程: " + Thread.currentThread().getId()+ " name:" + Thread.currentThread().getName());

      Thread.sleep(2000);
      Log.e("bm", "執(zhí)行完耗時操作了~");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
  }
};
new Thread() {
  public void run() {
    Looper.prepare();
    new Handler().post(runnable);//在子線程中直接去new 一個handler
    Looper.loop();    //這種情況下,Runnable對象是運行在子線程中的,可以進(jìn)行聯(lián)網(wǎng)操作,但是不能更新UI
  }
}.start();

方法2:通過Looper.getMainLooper(),獲得主線程的Looper,將其綁定到此Handler對象上。

final Runnable runnable = new Runnable() {
  @Override
  public void run() {
    //執(zhí)行耗時操作
    try {
      Log.e("bm", "runnable線程: " + Thread.currentThread().getId()+ " name:" + Thread.currentThread().getName());
      Thread.sleep(2000);
      Log.e("bm", "執(zhí)行完耗時操作了~");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
  }
};
new Thread() {
  public void run() {
      //在子線程中直接去new 一個handler
    new Handler(Looper.getMainLooper()).post(runnable);
    //這種情況下,Runnable對象是運行在主線程中的,不可以進(jìn)行聯(lián)網(wǎng)操作,但是可以更新UI
  }
}.start();

G.其他延申

3.2 platform-toolsadb.exe,start-server" failed -- run manually if necessary

A.詳細(xì)崩潰日志信息

B.查看崩潰類信息

C.項目中異常分析

adb啟動失敗,端口被占用

D.引發(fā)崩潰日志的流程分析

F.解決辦法

百度google大家多說的是任務(wù)管理器 kill掉adb 或者重啟adb server,但我任務(wù)管理器就沒有adb ,猜測是某個程序占用了adb端口。于是按此思路查找。
5037為adb默認(rèn)端口 查看該端口情況如下:
netstat -aon|findstr "5037"
TCP 127.0.0.1:5037 0.0.0.0:0 LISTENING 6540
發(fā)現(xiàn)6540占用了 5037端口,繼續(xù)查看6540的task,發(fā)現(xiàn)是wandoujia .如下所示
tasklist|findstr "6540"
wandoujia_daemon.exe 6540 Console 1 4,276 K

接下來問題就好解決了,在任務(wù)管理器kill掉wandoujia_daemon.exe ,運行android程序,ok .

1.關(guān)閉xx莢進(jìn)程
2.adb kill-server
3.adb start-server

G.其他延申

3.3 java.lang.IllegalStateException: ExpectedBEGIN_OBJECT but was STRING at line 1 column 1 path $

A.詳細(xì)崩潰日志信息

非法參數(shù),開始讀取時應(yīng)該是{}括號,所以需要處理String字符串,它有可能不是標(biāo)準(zhǔn)的json數(shù)據(jù)

java.lang.IllegalStateException: ExpectedBEGIN_OBJECT but was STRING at line 1 column 1 path $

B.查看崩潰類信息

C.項目中異常分析

Gson解析數(shù)據(jù)出現(xiàn)問題,原因服務(wù)器返回數(shù)據(jù)不嚴(yán)謹(jǐn)

D.引發(fā)崩潰日志的流程分析

可能的錯誤:

bean類字段類型和字段名稱不一致。

服務(wù)器訪問得到的字符串不是純json前面有空格和回車等字符(難發(fā)現(xiàn))。

如果訪問的json字符串不是utf-8編碼時,用Gson解析會出這種問題,在日志中打印會發(fā)現(xiàn)json的{}前面有亂碼字符,也需要注意一下。這是因為不同的編碼的原因?qū)е碌模虼吮仨氃L問utf-8的json字符串,才會減少這種問題。

問題可能是:字符串并不是純json字符串,開頭可能會帶有空字符或者回車符,這屬于服務(wù)器問題,但我們也可以解決。

最重要原因的我們網(wǎng)絡(luò)請求后結(jié)果是字符串,而不是json,因此需要處理。

F.解決辦法

/**

*/
public static boolean isJson(String value) {
    try {
        new JSONObject(value);
    } catch (JSONException e) {
        return false;
    }
    return true;
}

/**
* 判斷是否是json結(jié)構(gòu)
*/
public static boolean isGoodJson(String json) {
    try {
        new JsonParser().parse(json);
        return true;
    } catch (JsonParseException e) {
        System.out.println("bad json: " + json);
        return false;
    }
}
```

G.其他延申,補充說明

解決辦法:后臺輸出穩(wěn)定的Gson格式。此方法工程量太大

真正的問題是我的數(shù)據(jù)結(jié)構(gòu)有問題

例如下面Json字符串:

{"code":1,"info":"success","results":{"id":"1","name":"hehe"}}

results對應(yīng)的應(yīng)該是一個實體類,如果這個時候想把他解析為String或者List就會出現(xiàn)異常

如果參考使用GsonForm處理后的數(shù)據(jù)模型,幾乎不會出現(xiàn)問題;加入result后面的內(nèi)容可能在請求時會因為某些原因會存在格式上的變化,這個時候就有出現(xiàn)該異常的風(fēng)險。Gson中,關(guān)鍵字后面出現(xiàn)""引起來的內(nèi)容將會被只認(rèn)為是STRING,“{}”只被認(rèn)為是類,“[]”只被認(rèn)為是List,這個幾乎是強制性的。

就是說如果你的實體預(yù)計是獲取String的變量,但是關(guān)鍵字后面對應(yīng)的卻出現(xiàn)了“{”或“[”,那么這個轉(zhuǎn)換將被認(rèn)為是錯誤的,拋出異常。

3.4 android.content.ActivityNotFoundException: No Activity found to handle Intent

A.詳細(xì)崩潰日志信息

android.content.ActivityNotFoundException: No Activity found to handle Intent

B.查看崩潰類信息

當(dāng)調(diào)用{@link Context#startActivity}或其變體之一失敗時,會引發(fā)此異常,因為無法找到執(zhí)行給定意圖的活動。

public class ActivityNotFoundException extends RuntimeException
{
    public ActivityNotFoundException()
    {
    }

    public ActivityNotFoundException(String name)
    {
        super(name);
    }
};

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

F.解決辦法

第一種辦法:做一個try catch

Intent intent = new Intent(Intent.ACTION_SENDTO,url);
try {
    context.startActivity(intent);
} catch(ActivityNotFoundException exception) {
    Toast.makeText(this, "no activity", Toast.LENGTH_SHORT).show();
}

第二種辦法:判斷是否有應(yīng)用寶客戶端

//避免安裝了應(yīng)用寶的用戶點擊其他外部鏈接走此方法導(dǎo)致崩潰
//判斷是否用應(yīng)用寶客戶端
if(AppUtils.isPkgInstalled(AdDetailActivity.this,"com.tencent.android.qqdownloader")){
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    startActivity( intent);
}

3.5 Package manager has died導(dǎo)致崩潰

A.詳細(xì)崩潰日志信息

出錯代碼位置
public static String softVersionName(Context context) {
    PackageInfo info = null;
    try {
        info = context.getPackageManager().getPackageInfo( context.getPackageName(), 0);     //在這里
    } catch (NameNotFoundException e) {
        e.printStackTrace();
    }
    return info.versionName;
}

B.查看崩潰類信息

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

原因分析(Binder造成)

如果一個進(jìn)程中使用的Binder內(nèi)容超過了1M,就會crash.

如果Binder的使用超出了一個進(jìn)程的限制就會拋出TransactionTooLargeException這個異常。

如果是其他原因造成Binder crash的話就會拋出RuntimeException。

F.解決辦法

public static String softVersionName(Context context) {
    PackageInfo info = null;
    try {//增加同步塊
        synchronized (context) {
            info =context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
        }
        return info.versionName;
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

G.其他延申

private void test() {
        //這個Demo就是同時創(chuàng)建兩個線程來進(jìn)行Binder調(diào)用.
        for (int i = 0; i < 2; i++) {
            new Thread() {
                @Override
                public void run() {
                    int count = 0;
                    List list = getPackageManager().getInstalledPackages(0);
                    for (PackageInfo info : list) {
                        if(count >=1000){
                            break;
                        }
                        try {
                            PackageInfo pi = getPackageManager().getPackageInfo(info.packageName, PackageManager.GET_ACTIVITIES);
                        } catch (PackageManager.NameNotFoundException e) {

                        }
                    }
                }
            }.start();
        }
    }
}

錯誤打印日志

解決方式:其實只要避免多個線程同時來調(diào)用Binder就可以了,畢竟一個線程用了會釋放,所以理論上是很難發(fā)生的。

synchronized(MainActivity.class){ 
    PackageInfo pi = getPackageManager() .getPackageInfo(info.packageName, PackageManager.GET_ACTIVITIES); 
} 

3.6 IllegalArgumentException View添加窗口錯誤

A.詳細(xì)崩潰日志信息

View=com.android.internal.policy.impl.PhoneWindow$DecorView{22a4fb16 V.E..... R.....ID 0,0-1080,1020} not attached to window manager
com.flyco.dialog.widget.base.BaseDialog.superDismiss(BaseDialog.java)

B.查看崩潰類信息

C.項目中異常分析

該異常表示view沒有添加到窗口管理器,通常是我們dismiss對話框的時候,activity已經(jīng)不存在了,建議不要在非UI線程操作對話框。

D.引發(fā)崩潰日志的流程分析

常發(fā)生這類Exception的情形都是,有一個費時的線程操作,需要顯示一個Dialog,在任務(wù)開始的時候顯示一個對話框,然后當(dāng)任務(wù)完成了在Dismiss對話框,如果在此期間如果Activity因為某種原因被殺掉且又重新啟動了,那么當(dāng)dialog調(diào)用dismiss的時候WindowManager檢查發(fā)現(xiàn)Dialog所屬的Activity已經(jīng)不存在,所以會報錯。要避免此類Exception,就要正確的使用對話框,也要正確的使用線程

F.解決辦法

可以參考崩潰bug日志總結(jié)1中的1.7

G.其他延申,建議

不要在非UI線程中使用對話框創(chuàng)建,顯示和取消對話框;

盡量少用多帶帶線程,出發(fā)是真正的耗時操作采用線程,線程也不要直接用Java式的匿名線程,除非是那種單純的操作,操作完成不需要做其他事情的。

如果是在fragment中發(fā)起異步網(wǎng)絡(luò)的回調(diào)中進(jìn)行dialog的操作,那么在操作之前,需要判斷 isAdd( ),避免fragment被回收了但是還要求dialog去dismiss

在Activity onDestroy中對Dialog提前進(jìn)行關(guān)閉

3.7 IllegalStateException: Not allowed to start service Intent異常崩潰

A.詳細(xì)崩潰日志信息

 Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { act=initApplication cmp=com.paidian.hwmc/.service.InitializeService }: app is in background uid UidRecord{a37d28d u0a386 TRNB bg:+5m30s482ms idle procs:3 seq(0,0,0)}

B.查看崩潰類信息

C.項目中異常分析

D.引發(fā)崩潰日志的流程分析

F.解決辦法

G.其他延申

3.8 java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState

A.詳細(xì)崩潰日志信息

B.查看崩潰類信息

C.項目中異常分析

通過下面的源碼分析,我們可以知道,出現(xiàn)以上崩潰日志的原因,是因為我們在按下頁面返回鍵的時候,當(dāng)前Activity以及在執(zhí)行銷毀操作(也就是說我們以前在其他地方調(diào)用了finish方法)。

D.引發(fā)崩潰日志的流程分析

問題所在是Activity#onBackPressed()方法。查看源代碼:點擊onBackPressed方法中的super

在FragmentActivity中

@Override
public void onBackPressed() {
    if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
        super.onBackPressed();
    }
}

接著再次點擊super,在Activity中

public void onBackPressed() {
    if (mActionBar != null && mActionBar.collapseActionView()) {
        return;
    }

    if (!mFragments.getFragmentManager().popBackStackImmediate()) {
        finishAfterTransition();
    }
}
public void finishAfterTransition() {
    if (!mActivityTransitionState.startExitBackTransition(this)) {
        finish();
    }
}

我們看到onBackPressed()方法執(zhí)行了兩個操作,第一個是獲取當(dāng)前的FragmentManager,并且執(zhí)行退棧操作,第二個是在退棧完成之后,執(zhí)行finish方法。繼續(xù)查看源碼,關(guān)鍵是FragmentManager實現(xiàn)類的popBackStackImmediate方法

@Override
public boolean popBackStackImmediate() {
    checkStateLoss();
    executePendingTransactions();
    return popBackStackState(mHost.getHandler(), null, -1, 0);
}

我們看到,在執(zhí)行退棧動作之前,這里還有一步檢查操作

private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }
}

從這里,我們終于找到了崩潰日志上的異常文案:Can not perform this action after onSaveInstanceState

F.解決辦法

方案1,在調(diào)用super.onBackPressed的時候,我們需要判斷當(dāng)前Activity是否正在執(zhí)行銷毀操作。

if (!isFinishing()) {
    super.onBackPressed();
}

方案2,通過上面的源碼分析,我們也知道了,super.onBackPressed最后也是調(diào)用finish()方法,因此我們可以重寫onBackPressed,直接調(diào)用finish方法。

G.其他延申

3.9 在Fragment中通過getActivity找不到上下文,報null導(dǎo)致空指針異常

A.詳細(xì)崩潰日志信息

B.查看崩潰類信息

C.項目中異常分析

使用ViewPager+Fragment進(jìn)行視圖滑動,在某些部分邏輯也許我們需要利用上下文Context(例如基本的Toast),但是由于Fragment只是衣服在Activity容器的一個試圖,如果需要拿到當(dāng)前的Activity的上下文Context就必須通過getActivity()獲取。

遇過出現(xiàn)getActivity()出現(xiàn)null的時候?qū)е鲁绦驁蟪隹罩羔槷惓!F鋵嵲蚩梢詺w結(jié)于因為我們在

切換fragment的時候,會頻繁被crash

系統(tǒng)內(nèi)存不足

橫豎屏幕切換的時候

以上情況都會導(dǎo)致Activity被系統(tǒng)回收,但是由于fragment的生命周期不會隨著Actiivty被回收而被回收,因此才會導(dǎo)致getActivity()出現(xiàn)null的問題。

很多人都曾被這個問題所困擾,如果app長時間在后臺運行,再次進(jìn)入app的時候可能會出現(xiàn)crash,而且fragment會有重疊現(xiàn)象。如果系統(tǒng)內(nèi)存不足、切換橫豎屏、app長時間在后臺運行,Activity都可能會被系統(tǒng)回收然后重建,但Fragment并不會隨著Activity的回收而被回收,創(chuàng)建的所有Fragment會被保存到Bundle里面,從而導(dǎo)致Fragment丟失對應(yīng)的Activity。

D.引發(fā)崩潰日志的流程分析

當(dāng)遇到getActivity()為null,或getContext()時,先冷靜想想以下3點:

1.是不是放在了第三方的回調(diào)中

2.是不是在其他進(jìn)程中調(diào)用了(其實第一點就是在其他進(jìn)程中調(diào)用了)

3.是不是調(diào)用時不在指定生命周期范圍內(nèi)(onAttach與onDetach之間)

F.解決辦法

在Fragment中直接調(diào)用
private MActivity mActivity; 
@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    mActivity = (MActivity) activity; 
}
@Override
public void onDetach() {
    super.onDetach();
    mActivity = null;
}

G.其他延申

源碼解讀:在FragmentActivity中

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Parcelable p = mFragments.saveAllState();
    if (p != null) {
        outState.putParcelable(FRAGMENTS_TAG, p);
    }
    ……
}

如果從最近使用的應(yīng)用里面點擊我們的應(yīng)用,系統(tǒng)會恢復(fù)之前被回收的Activity,這個時候FragmentActivity在oncreate里面也會做Fragment的恢復(fù)

@SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    mFragments.attachHost(null /*parent*/);
    super.onCreate(savedInstanceState);
    NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
    if (nc != null) {
        mFragments.restoreLoaderNonConfig(nc.loaders);
    }
    if (savedInstanceState != null) {
        Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
        mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
  ……
    }
    if (mPendingFragmentActivityResults == null) {
        mPendingFragmentActivityResults = new SparseArrayCompat<>();
        mNextCandidateRequestIndex = 0;
    }
    mFragments.dispatchCreate();
}

假設(shè)我們的頁面叫MyActivity(繼承自FragmentActivity),其中用到的Fragment叫MyFragment。出現(xiàn)上面這種情況時,app發(fā)生的變化如下:

1、在前面提到的幾種情況下系統(tǒng)回收了MyActivity

2、通過onSaveInstanceState保存MyFragment的狀態(tài)

3、用戶再次點擊進(jìn)入app

4、由于MyActivity被回收,系統(tǒng)會重啟MyActivity,根據(jù)之前保存的MyFragment的狀態(tài)恢復(fù)fragment

5、MyActivity的代碼邏輯中,會再次創(chuàng)建新的MyFragment

6、頁面出現(xiàn)混亂,覆蓋了兩層的fragment。假如恢復(fù)的MyFragment使用到了getActivity()方法,會報空指針異常

對于上面的問題,可以考慮下面這兩種解決辦法:

1、不保存fragment的狀態(tài):在MyActivity中重寫onSaveInstanceState方法,將super.onSaveInstanceState(outState);注釋掉,讓其不再保存Fragment的狀態(tài),達(dá)到fragment隨MyActivity一起銷毀的目的。

2、重建時清除已經(jīng)保存的fragment的狀態(tài):在恢復(fù)Fragment之前把Bundle里面的fragment狀態(tài)數(shù)據(jù)給清除。方法如下:

if(savedInstanceState!= null){
    String FRAGMENTS_TAG =  "Android:support:fragments";
    savedInstanceState.remove(FRAGMENTS_TAG);
}

4.1 IllegalArgumentException導(dǎo)致崩潰【url地址傳入非法參數(shù),轉(zhuǎn)義字符】

A.詳細(xì)崩潰日志信息

B.查看崩潰類信息

C.項目中異常分析

只有很少一部分傳入非法參數(shù)導(dǎo)致崩潰,不能直接用常規(guī)方法。需要過濾

D.引發(fā)崩潰日志的流程分析

F.解決辦法

Java調(diào)用 URLDecoder.decode(str,"UTF-8");拋出以上的異常,其主要原因是%在URL中是特殊字符,需要特殊轉(zhuǎn)義一下

public static String replacer(String data) {
    try {
        //使用%25替換字符串中的%號
        data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");      
        data = URLDecoder.decode(data, "utf-8");
    } catch (Exception e) {
        e.printStackTrace();
    }
    return data;
}

4.2 ClassNotFoundException: Didn"t find class "" on path: /data/app/*錯誤

A.詳細(xì)崩潰日志信息

java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{*****Activity}: java.lang.ClassNotFoundException: Didn"t find class "*****Activity" on path: /data/app/*******.apk

B.查看崩潰類信息

當(dāng)應(yīng)用程序嘗試使用字符串名稱加載類時引發(fā):但無法找到具有指定名稱的類的定義。從1.4版開始,已對此異常進(jìn)行了修改,以符合通用的異常鏈接機制。在構(gòu)建時提供并通過{@link#getException()}方法訪問的“在加載類時引發(fā)的可選異常”現(xiàn)在稱為原因,并且可以通過{@link Throwable#getCace()}方法以及前面提到的“遺留方法”進(jìn)行訪問。

public class ClassNotFoundException extends ReflectiveOperationException {
    private static final long serialVersionUID = 9176873029745254542L;
    private Throwable ex;
    public ClassNotFoundException() {
        super((Throwable)null);  // Disallow initCause
    }
    public ClassNotFoundException(String s) {
        super(s, null);  //  Disallow initCause
    }
    public ClassNotFoundException(String s, Throwable ex) {
        super(s, null);  //  Disallow initCause
        this.ex = ex;
    }
    public Throwable getException() {
        return ex;
    }
    public Throwable getCause() {
        return ex;
    }
}

C.項目中異常分析

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75919.html

相關(guān)文章

  • Android開發(fā)經(jīng)驗實戰(zhàn)總結(jié)

    摘要:以前一直想寫一篇總結(jié)開發(fā)經(jīng)驗的文章,估計當(dāng)時的我還達(dá)不到某種水平,所以思路跟不上,下筆又捉襟見肘。在需求都還沒完成的時候把大量時間花在優(yōu)化上是本末倒置的優(yōu)化要用實際數(shù)據(jù)說話,借助測試工具進(jìn)行檢測如網(wǎng)易的騰訊的和,科大訊飛的,的。 以前一直想寫一篇總結(jié) Android 開發(fā)經(jīng)驗的文章,估計當(dāng)時的我還達(dá)不到某種水平,所以思路跟不上,下筆又捉襟見肘。近日,思路較為明朗,于是重新操起鍵盤開始碼...

    iflove 評論0 收藏0
  • Android性能優(yōu)化之內(nèi)存優(yōu)化

    摘要:導(dǎo)語智能手機發(fā)展到今天已經(jīng)有十幾個年頭,手機的軟硬件都已經(jīng)發(fā)生了翻天覆地的變化,特別是陣營,從一開始的一兩百到今天動輒,內(nèi)存。恰好最近做了內(nèi)存優(yōu)化相關(guān)的工作,這里也對內(nèi)存優(yōu)化相關(guān)的知識做下總結(jié)。 導(dǎo)語 智能手機發(fā)展到今天已經(jīng)有十幾個年頭,手機的軟硬件都已經(jīng)發(fā)生了翻天覆地的變化,特別是Android陣營,從一開始的一兩百M到今天動輒4G,6G內(nèi)存。然而大部分的開發(fā)者觀看下自己的異常上報系...

    cheng10 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<