App的異常崩潰處理

做任何軟件戚绕,都需要考慮異常情況的處理粉臊,這是軟件的可維護性的一部分。
異常崩潰是一種罕見的極端異常情況硬萍,這種情況下,針對終端用戶的UI反饋虎锚、事故設(shè)備的信息采集硫痰、向后臺維護人員的數(shù)據(jù)反饋等,都需要精心的設(shè)計窜护。

UI反饋

  • 要做反饋效斑,首先要抓到所有的異常崩潰。
    異常崩潰都是App進程的異常柱徙,每個App進程都運行在該App的Application中缓屠,所以我們可以在Application上集中抓到所有的進程異常:
    private Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
    private Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
        if (uncaughtExceptionHandler == null) {
            uncaughtExceptionHandler = CrashHandler.getInstance(this,this);
        }
        return uncaughtExceptionHandler;
    }
    private void init(){
        Thread.setDefaultUncaughtExceptionHandler(getUncaughtExceptionHandler());
    }

我們抓到所有的進程異常,然后統(tǒng)一拋給一個CrashHandler類去處理护侮,這個CrashHandler要實現(xiàn)UncaughtExceptionHandler接口:

public class CrashHandler implements UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
    }
}
  • 盡力保持用戶數(shù)據(jù)的完整性敌完,并設(shè)法恢復崩潰前的界面。
    如果要在崩潰時重啟App羊初,就需要在退出App前滨溉,再次StartActivity
            Intent i = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            mContext.startActivity(i);
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(0);

其中,android.os.Process.killProcess(Dalvik虛擬機方法)和System.exit(0)(常規(guī)java方法)起到的作用一樣长赞。
這里有一個關(guān)于Activity棧的陷阱晦攒,上面的代碼可以重啟入口Activity,但是得哆,如果這時你這個App的Activity棧里還有其他的Activity脯颜,這些Activity是仍然存在的,不會被銷毀贩据。
推薦的做法是在Application中維護一個Activity的列表伐脖,專門管理所有的Activity,在必要時乐设,通過這個列表讼庇,去銷毀所有的Activity

    private ActivityStack stack;//擴展LinkList自定義一個activity列表
    //用set注入
    @Override
    public void initActivityStack(ActivityStack stack) {
        this.stack=stack;
    }
    //activity在oncreate時做添加//
    @Override
    public void addActivity(Activity activity) {
        if(stack!=null)stack.addStack(activity);
    }
    //activity在ondestroy時做刪減//
    @Override
    public void removeActivity(Activity activity) {
        if(stack!=null)stack.remove(activity);
    }
    @Override
    public void clearAll() {
        if(stack!=null)stack.clearAll();
    }

在這個自定義的activity列表里,通過調(diào)用Activity的finish近尚,來銷毀Activity

public void clearAll() {
        if(stack!=null&&stack.size()>0) {
            for (Activity activity : stack) {
                if (activity != null) {
                    activity.finish();
                }
            }
            stack.clear();
        }
    }

注意蠕啄,為了避免Application持有Activity導致內(nèi)存泄露,在Activity的生命周期里不能只寫入列戈锻,還要記得寫出列歼跟。

  • 然后要提示用戶發(fā)生了一些事情,這里要謹慎措辭格遭,最好根據(jù)產(chǎn)品特性設(shè)計一些符合產(chǎn)品氣質(zhì)的提示語哈街,這里就不展開了。
  • 最后拒迅,在自動重啟和退出App之間尋找平衡骚秦,比如第一次崩潰當然可以自動重啟她倘,如果遇到特殊因素導致連續(xù)崩潰(如:接口問題或運行環(huán)境問題),就需要人為限制重啟的次數(shù)或頻率(比如作箍,記錄上次自動重啟的時間硬梁,判斷兩次重啟的時間間隔是否過窄),避免成為用戶眼中的流氓軟件胞得。

信息采集

對異常崩潰了解的越多荧止,就越容易處理它,所以我們要盡可能地采集相關(guān)信息阶剑。
對研發(fā)來說跃巡,最有用的當然是異常代碼行(如MainActivity第61行)和異常原因(如空指針異常),在研發(fā)環(huán)境里牧愁,我們可以通過logcat讀到這些信息素邪,那沒什么可說的,我們要考慮的是递宅,如果異常崩潰發(fā)生在萬里之外的生產(chǎn)環(huán)境,我們要怎樣采集信息苍狰。

  • 首先办龄,要創(chuàng)建和保存本地log文件夾,專門保存這些信息淋昭,一方面俐填,網(wǎng)絡(luò)不是一直可靠的,保存到本地可以避免數(shù)據(jù)丟失翔忽;另一方面英融,無論是遠程數(shù)據(jù)上傳還是現(xiàn)場同僚手動拷貝,都需要有這樣一個文件夾歇式。
  • 然后驶悟,要抓取異常代碼行和異常原因,也就是你在logcat里讀到的那些異常堆棧信息材失,所有的Java異常都會拋出一個Throwable痕鳍,這里面就能找到這些異常堆棧信息(需要用printwriter去讀)
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();

        String result = writer.toString();
  • 最后,有些崩潰是在特定的軟硬件環(huán)境下出現(xiàn)的龙巨,我們需要知道這些環(huán)境信息:
        Map<String, String> infos = new HashMap<String, String>();
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                infos.put(field.getName(), field.get(null).toString());
            } catch (Exception e) {
                Log.e(TAG, "an error occured when collect crash info", e);
            }
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> entry : infos.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key + "=" + value + "\n");
        }

數(shù)據(jù)反饋

首選當然是通過后臺網(wǎng)絡(luò)默默反饋(在WIFI環(huán)境下笼呆,避免消耗用戶流量)。
如果是以文件為單位上傳反饋旨别,只要做好鎖文件和銷毀文件即可诗赌。
如果是在線實時上傳反饋,就需要為每次崩潰編號秸弛,或根據(jù)編號依次上傳铭若,或在后臺進行合并過濾洪碳。
需要注意的是,本地日志文件不能過大奥喻,如果超過一定大小限制偶宫,要有自動清理機制,比如刪除日期最早的那個文件环鲤,是的纯趋,強烈建議根據(jù)日期來建立多個日志文件。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冷离,一起剝皮案震驚了整個濱河市吵冒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌西剥,老刑警劉巖痹栖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瞭空,居然都是意外死亡揪阿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門咆畏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來南捂,“玉大人,你說我怎么就攤上這事旧找∧缃。” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵钮蛛,是天一觀的道長鞭缭。 經(jīng)常有香客問我,道長魏颓,這世上最難降的妖魔是什么岭辣? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮甸饱,結(jié)果婚禮上易结,老公的妹妹穿的比我還像新娘。我一直安慰自己柜候,他們只是感情好搞动,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渣刷,像睡著了一般鹦肿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辅柴,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天箩溃,我揣著相機與錄音瞭吃,去河邊找鬼。 笑死涣旨,一個胖子當著我的面吹牛歪架,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霹陡,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼和蚪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了烹棉?” 一聲冷哼從身側(cè)響起攒霹,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浆洗,沒想到半個月后催束,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡伏社,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年抠刺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摘昌。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡速妖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出第焰,到底是詐尸還是另有隱情买优,我是刑警寧澤妨马,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布挺举,位于F島的核電站,受9級特大地震影響烘跺,放射性物質(zhì)發(fā)生泄漏湘纵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一滤淳、第九天 我趴在偏房一處隱蔽的房頂上張望梧喷。 院中可真熱鬧,春花似錦脖咐、人聲如沸铺敌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽偿凭。三九已至,卻和暖如春派歌,著一層夾襖步出監(jiān)牢的瞬間弯囊,已是汗流浹背痰哨。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留匾嘱,地道東北人斤斧。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像霎烙,于是被迫代替她去往敵國和親撬讽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容