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

資訊專欄INFORMATION COLUMN

如何優(yōu)雅的退出應(yīng)用和處理崩潰異常并重啟

learn_shifeng / 579人閱讀

摘要:退出應(yīng)用的幾種方式退出應(yīng)用的方式很多,常見的也就下面四種。當(dāng)發(fā)生時(shí)會(huì)轉(zhuǎn)入該函數(shù)來處理如果用戶沒有處理則讓系統(tǒng)默認(rèn)的異常處理器來處理如果需要重啟重啟應(yīng)用,得使用重啟應(yīng)用結(jié)束應(yīng)用我們的方法用于彈出和收集信息。

寫在前面

這是最近一些朋友問我的問題,我把它整理成了一個(gè)庫(kù),供大家享用,GitHub 地址:https://github.com/nanchen2251/AppManager

從四個(gè)應(yīng)用場(chǎng)景說起

退出應(yīng)用
相信各位朋友或多或少都會(huì)有遇到過需要在某個(gè)特定的地方退出應(yīng)用的需求,這個(gè)場(chǎng)景一定非常普遍。

崩潰后重啟
程序總是無法做到盡善盡美,有時(shí)候你也不知道因?yàn)槭裁丛驅(qū)е铝?APP 的崩潰,這無疑是非常糟糕的用戶體驗(yàn)。這時(shí)候我們可以采用重啟機(jī)制來增強(qiáng)用戶舒適體驗(yàn)感。

莫名其妙重啟
然而心細(xì)的小伙伴肯定會(huì)發(fā)現(xiàn),在部分手機(jī)上會(huì)出現(xiàn)莫名其妙的崩潰后重啟(后面會(huì)講原因),而且最要命的是,假設(shè)你有三個(gè) Activity,他們分別是 Act1, Act2, Act3,它們的啟動(dòng)順序是 Act1 -> Act2 -> Act3,而如果在 Act3 發(fā)生了崩潰,這時(shí)候極有可能應(yīng)用重啟后進(jìn)入的是 Act2,而 Act2 中需要某個(gè)來源于 Act1 (或者在 Act1 中通過接口獲取) 的參數(shù),當(dāng)沒有這個(gè)參數(shù)的時(shí)候會(huì)引發(fā)崩潰(或者數(shù)據(jù)不全)。這時(shí)候你可能最直觀的想法就是禁止應(yīng)用重啟,但或許這并不是最佳的方式。

崩潰時(shí)彈出一個(gè)對(duì)話框
在部分手機(jī)上,當(dāng)崩潰的時(shí)候,會(huì)彈出一個(gè)提示對(duì)話框。在這種情況下,用戶只有點(diǎn)擊 “強(qiáng)行關(guān)閉” 來結(jié)束程序。當(dāng)該對(duì)話框出現(xiàn),對(duì)用戶來說是相當(dāng)不友好的。或許我們可以通過某種方式攔截掉系統(tǒng)的處理,讓應(yīng)用出錯(cuò)時(shí)不再顯示它。

退出應(yīng)用的幾種方式

Andorid 退出應(yīng)用的方式很多,常見的也就下面四種。

System.exit(0) 使用系統(tǒng)的方法,強(qiáng)制退出
System.exit(0) 表示的是終止程序,終止當(dāng)前正在運(yùn)行的?Java 虛擬機(jī),在 Java 中我們也使用這種方式來關(guān)閉整個(gè)應(yīng)用,在前期很多開發(fā)人員都是使用這種方式,我自己在開發(fā)項(xiàng)目過程中也用過這種方式來退出,但是有時(shí)候會(huì)在部分機(jī)型中,當(dāng)退出應(yīng)用后彈出應(yīng)用程序崩潰的對(duì)話框,有時(shí)退出后還會(huì)再次啟動(dòng),少部分的用戶體驗(yàn)不太好。但現(xiàn)在也依舊還會(huì)有少部分的開發(fā)人員會(huì)使用這種方式,因?yàn)槭褂梅绞胶芎?jiǎn)單,只需要在需要退出的地方加上這句代碼就行。

拋出異常,強(qiáng)制退出
這種方式現(xiàn)在基本上已經(jīng)看不到了,用戶體驗(yàn)比第一種方式更差,就是讓拋出異常、是系統(tǒng)崩潰、從而達(dá)到退出應(yīng)用的效果

使用 Application 退出
目前比較常用方法之一,我們都知道 ApplicationAndroid 的系統(tǒng)組件,當(dāng)應(yīng)用程序啟動(dòng)時(shí),會(huì)自動(dòng)幫我們創(chuàng)建一個(gè) Application,而且一個(gè)應(yīng)用程序只能存在一個(gè) Application ,它的生命周期也是最長(zhǎng)的,如果需要使用自己創(chuàng)建的 Application 時(shí),這個(gè)時(shí)候我們只需要在 Androidmanifest.xml 中的 標(biāo)簽中添加 name 屬性:把創(chuàng)建的 Application 完整的包名 + 類名放進(jìn)了就行了。

使用廣播退出
使用廣播來實(shí)現(xiàn)退出應(yīng)用程序,其實(shí)實(shí)現(xiàn)的思路相對(duì)于第三種更簡(jiǎn)單,我們編寫一個(gè) BaseActivity,讓其他的 Activity 都繼承于它,當(dāng)我需要退出時(shí),我們就銷毀 BaseActivity,那么其他繼承與它的 Activity 都會(huì)銷毀。

四種方式的代碼也就不多提,需要的自己去Android:銷毀所有的Activity退出應(yīng)用程序幾種方式

莫名其妙重啟?

上面的場(chǎng)景中說到了,再部分手機(jī)上會(huì)出現(xiàn)崩潰后自動(dòng)重啟的情況,這讓我們很不好控制。經(jīng)本人測(cè)試,在 Android 的 API 21 ( Android 5.0 ) 以下,Crash 會(huì)直接退出應(yīng)用,但是在 API 21 ( Android 5.0 ) 以上,系統(tǒng)會(huì)遵循以下原則進(jìn)行重啟:

包含 Service,如果應(yīng)用 Crash 的時(shí)候,運(yùn)行著 Service,那么系統(tǒng)會(huì)重新啟動(dòng) Service。

不包含 Service,只有一個(gè) Activity,那么系統(tǒng)不會(huì)重新啟動(dòng)該 Activity。

不包含 Service,但當(dāng)前堆棧中存在兩個(gè) Activity:Act1 -> Act2,如果 Act2 發(fā)生了 Crash ,那么系統(tǒng)會(huì)重啟 Act1。

不包含 Service,但是當(dāng)前堆棧中存在三個(gè) Activity:Act1 -> Act2 -> Act3,如果 Act3 崩潰,那么系統(tǒng)會(huì)重啟 Act2,并且 Act1 依然存在,即可以從重啟的 Act2 回到 Act1。

在這樣的情況下,我們或許會(huì)有兩種需求:

崩潰后不允許重啟

崩潰后需要重啟

怎么辦

翻看 API 我們發(fā)現(xiàn),Java 中存在一個(gè) UncaughtExceotionHandler 的接口,而在 Android 中我們沿用了它,我們可以采用這個(gè)接口實(shí)現(xiàn)我們想要的功能。
(為了方便,我把它做成了庫(kù),傳送門:https://github.com/nanchen2251/AppManager)

講一些核心 CrashApplication

首先是我們的 CrashApplication 類,因?yàn)槲覀儽罎⒌臅r(shí)候需要結(jié)束程序后再重啟,所以我們需要退出應(yīng)用,這里我們采用上面的第三種方式。

public class CrashApplication extends Application {
    private List mActivityList;


    @Override
    public void onCreate() {
        super.onCreate();
        mActivityList = new ArrayList<>();
    }

    /**
     * 添加單個(gè)Activity
     */
    public void addActivity(Activity activity) {
        // 為了避免重復(fù)添加,需要判斷當(dāng)前集合是否滿足不存在該Activity
        if (!mActivityList.contains(activity)) {
            mActivityList.add(activity); // 把當(dāng)前Activity添加到集合中
        }
    }

    /**
     * 銷毀單個(gè)Activity
     */
    public void removeActivity(Activity activity) {
        // 判斷當(dāng)前集合是否存在該Activity
        if (mActivityList.contains(activity)) {
            mActivityList.remove(activity); // 從集合中移除
            if (activity != null){
                activity.finish(); // 銷毀當(dāng)前Activity
            }
        }
    }

    /**
     * 銷毀所有的Activity
     */
    public void removeAllActivity() {
        // 通過循環(huán),把集合中的所有Activity銷毀
        for (Activity activity : mActivityList) {
            if (activity != null){
                activity.finish();
            }
        }
        //殺死該應(yīng)用進(jìn)程
        android.os.Process.killProcess(android.os.Process.myPid());
    }

}
UncaughtExceptionHandlerImpl

我們當(dāng)然少不了新建一個(gè) UncaughtExceptionHandlerImpl 類去實(shí)現(xiàn)我們的 UncaughtExceptionHandler 接口,它必須實(shí)現(xiàn)我們的 uncaughtException(thread, throwable) 方法,我們接下來可以在這中間作文章。需要特別注意的是:重啟必須清除堆棧內(nèi)的 Activity。

/**
     * 當(dāng) UncaughtException 發(fā)生時(shí)會(huì)轉(zhuǎn)入該函數(shù)來處理
     */
    @SuppressWarnings("WrongConstant")
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultHandler != null) {
            // 如果用戶沒有處理則讓系統(tǒng)默認(rèn)的異常處理器來處理
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Log.e(TAG, "error : ", e);
            }
            if (mIsRestartApp) { // 如果需要重啟
                Intent intent = new Intent(mContext.getApplicationContext(), mRestartActivity);
                AlarmManager mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
                //重啟應(yīng)用,得使用PendingIntent
                PendingIntent restartIntent = PendingIntent.getActivity(
                        mContext.getApplicationContext(), 0, intent,
                        Intent.FLAG_ACTIVITY_NEW_TASK);
                mAlarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + mRestartTime,
                        restartIntent); // 重啟應(yīng)用
            }
            // 結(jié)束應(yīng)用
            ((CrashApplication) mContext.getApplicationContext()).removeAllActivity();
        }
    }

我們的 handleException(throwable) 方法用于彈出 Toast 和收集 Crash 信息。

  /**
     * 自定義錯(cuò)誤處理,收集錯(cuò)誤信息,發(fā)送錯(cuò)誤報(bào)告等操作均在此完成
     *
     * @param ex
     * @return true:如果處理了該異常信息;否則返回 false
     */
    private boolean handleException(final Throwable ex) {
        if (ex == null) {
            return false;
        }

        // 使用 Toast 來顯示異常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(mContext, getTips(ex), Toast.LENGTH_LONG).show();
                Looper.loop();
            }
        }.start();


        //  如果用戶不賦予外部存儲(chǔ)卡的寫權(quán)限導(dǎo)致的崩潰,會(huì)造成循環(huán)崩潰
//        if (mIsDebug) {
//            // 收集設(shè)備參數(shù)信息
//            collectDeviceInfo(mContext);
//            // 保存日志文件
//            saveCrashInfo2File(ex);
//        }
        return true;
    }
封裝好的使用 1、添加依賴
Step 1. Add it in your root build.gradle at the end of repositories:
allprojects {
        repositories {
            ...
            maven { url "https://jitpack.io" }
        }
    }
Step 2. Add the dependency
dependencies {
            compile "com.github.nanchen2251:AppManager:1.0.1"
    }
2、在需要使用的地方使用
// 設(shè)置崩潰后自動(dòng)重啟 APP
UncaughtExceptionHandlerImpl.getInstance().init(this, BuildConfig.DEBUG, true, 0, MainActivity.class);
3、你也可以禁止重啟
// 禁止重啟UncaughtExceptionHandlerImpl.getInstance().init(this,BuildConfig.DEBUG);

歡迎關(guān)注我的技術(shù)公眾號(hào)(公眾號(hào)搜索nanchen),每天一篇 Android 資源分享。

效果圖

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

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

相關(guān)文章

  • [譯]Express在生產(chǎn)環(huán)境下最佳實(shí)踐 - 性能可靠性

    摘要:前言這將是一個(gè)分為兩部分,內(nèi)容是關(guān)于在生產(chǎn)環(huán)境下,跑應(yīng)用的最佳實(shí)踐。第一部分會(huì)關(guān)注安全性,第二部分則會(huì)關(guān)注性能和可靠性。關(guān)于第一部分,請(qǐng)參閱在生產(chǎn)環(huán)境下的最佳實(shí)踐安全性。 前言 這將是一個(gè)分為兩部分,內(nèi)容是關(guān)于在生產(chǎn)環(huán)境下,跑Express應(yīng)用的最佳實(shí)踐。第一部分會(huì)關(guān)注安全性,第二部分則會(huì)關(guān)注性能和可靠性。當(dāng)你讀這篇文章時(shí),會(huì)假設(shè)你已經(jīng)對(duì)Node.js和web開發(fā)有所了解,并且對(duì)生產(chǎn)環(huán)...

    Luosunce 評(píng)論0 收藏0
  • 斷開TCP連接

    摘要:我們知道通過三次握手建立可靠連接,通過四次揮手?jǐn)嚅_連接,連接是比較昂貴的資源。從上分析,安全可靠的斷開連接至少需要四次,再多一次的意義不大。連接的異常斷開以上都是在理想的情況下發(fā)生的,理想狀態(tài)下,一個(gè)連接可以被長(zhǎng)期保持。 我們知道TCP通過三次握手建立可靠連接,通過四次揮手?jǐn)嚅_連接,TCP連接是比較昂貴的資源。為什么TCP需要通過三次握手才能建立可靠的連接??jī)纱尾恍忻矗繑嚅_連接為什么需...

    fyber 評(píng)論0 收藏0
  • 如何優(yōu)雅處理前端異常

    摘要:二需要處理哪些異常對(duì)于前端來說,我們可做的異常捕獲還真不少。總結(jié)一下,大概如下語法錯(cuò)誤代碼異常請(qǐng)求異常靜態(tài)資源加載異常異常異常跨域崩潰和卡頓下面我會(huì)針對(duì)每種具體情況來說明如何處理這些異常。 前端一直是距離用戶最近的一層,隨著產(chǎn)品的日益完善,我們會(huì)更加注重用戶體驗(yàn),而前端異常卻如鯁在喉,甚是煩人。一、為什么要處理異常?異常是不可控的,會(huì)影響最終的呈現(xiàn)結(jié)果,但是我們有充分的理由去做這樣的事...

    zoomdong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<