【Android】App 或 Activity 銷(xiāo)毀重建的狀態(tài)恢復(fù)對(duì)回調(diào)帶來(lái)的影響

問(wèn)題背景

在開(kāi)發(fā) PassportSDK 時(shí)遇到的此類(lèi)問(wèn)題,測(cè)試反饋說(shuō)當(dāng)打開(kāi) App 進(jìn)入登錄頁(yè)面,此時(shí)如果切換出去到手機(jī)設(shè)置頁(yè)面將App 的定位權(quán)限設(shè)置為「拒絕授予」,在切換回 App 會(huì)發(fā)生登錄信息完全正確也登錄不上的情況。

問(wèn)題分析

經(jīng)過(guò)抓包及打斷點(diǎn)查找問(wèn)題根源,發(fā)現(xiàn)是用戶在操作應(yīng)用權(quán)限授予時(shí),App 對(duì)象及 Activity 經(jīng)過(guò)了銷(xiāo)毀重建,此時(shí)一些基礎(chǔ)的 UI 狀態(tài)數(shù)據(jù)可以通過(guò) onSaveInstanceBundle 方法進(jìn)行保存,在 onCreate 方法中取出保存的狀態(tài)進(jìn)行恢復(fù)。但是登陸成功的回調(diào) loginListener 由于無(wú)法序列化且是隨著啟動(dòng)視圖的方法設(shè)置進(jìn)來(lái)的,所以無(wú)法恢復(fù)。這造成系統(tǒng)恢復(fù)的 Activity 對(duì)象持有的回調(diào) loginListener 為空,所以即使用戶輸入的登陸信息完全正確也無(wú)法登陸。

問(wèn)題解決及帶來(lái)的思考

今后的開(kāi)發(fā)中,要避免這種無(wú)法序列化的回調(diào)類(lèi)實(shí)例等與啟動(dòng)視圖的方法綁定的 Case,例如,PassportSDK 中啟動(dòng)登錄頁(yè)面的方法如下:

public void login(int loginType, MCLoginListener listener) {
    LoginActivity.setLoginListener(listener);
    Intent intent = new Intent(Global.getContext(), LoginActivity.class);
    intent.putExtra(LOGIN_TYPE, loginType);
    Global.getContext().startActivity(intent);
}

可以看到上面的方法中,我們將設(shè)置登錄回調(diào)的步驟放在了啟動(dòng)視圖的方法中。這在平時(shí)并沒(méi)有什么問(wèn)題,我們只需要在某個(gè)按鈕的點(diǎn)擊事件中調(diào)用此方法,傳入一個(gè)回調(diào),即可完成正常的業(yè)務(wù)邏輯。修改之前的代碼邏輯如下:

public class ActivityDemo extend Activity {
    MCLoginListener mListener = new MCLoginListener() {
        public void onSuccess(){
            //TODO
        }

        public void onError(){
            //TODO
        }

    }
    public void onCreate(Bundle savedInstanceBundle) {
        Button btn = findViewById(R.id.btn);
        btn.setOnClickListener(v -> {
            login(Global.CODE_PSD_LOGIN, mListener);
        })    
    }
}

但是假如 App 經(jīng)過(guò)上述的權(quán)限更改、屏幕旋轉(zhuǎn)、在后臺(tái)時(shí)間過(guò)久等場(chǎng)景,導(dǎo)致 App 對(duì)象及 Activity 銷(xiāo)毀重建時(shí),由于重建的 Activity 不是通過(guò)上述的啟動(dòng)視圖的方法展示的,并且在 Activity 中也無(wú)法將回調(diào)類(lèi)對(duì)象序列化并恢復(fù),所以我們以后一定要記住需要將回調(diào)與啟動(dòng)視圖的方法分離開(kāi)來(lái),并在上文對(duì)象(上個(gè)頁(yè)面 Activity 對(duì)象或 App 對(duì)象)的 onCreate 生命周期中重新調(diào)用設(shè)置回調(diào)的方法即可。修改之后的代碼如下:

public class ActivityDemo extend Activity {
    MCLoginListener mListener = new MCLoginListener() {
        public void onSuccess(){
            //TODO
        }

        public void onError(){
            //TODO
        }

    }
    public void onCreate(Bundle savedInstanceBundle) {
        // 放在這里可以保證系統(tǒng)恢復(fù)此上文 Activity 時(shí)就為 LoginActivity 添加了回調(diào)類(lèi)實(shí)例
        LoginActivity.setLoginListener(listener);
        Button btn = findViewById(R.id.btn);
        btn.setOnClickListener(v -> {
            login(Global.CODE_PSD_LOGIN);
        })    
    }

    // 只保留純粹的啟動(dòng)視圖方法
    public void login(int loginType) {
        Intent intent = new Intent(Global.getContext(), LoginActivity.class);
        intent.putExtra(LOGIN_TYPE, loginType);
        Global.getContext().startActivity(intent);
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 學(xué)習(xí)資料: Android群英傳 Android開(kāi)發(fā)藝術(shù)探索 Activity是與用戶交互的第一接口,感覺(jué)說(shuō)是四大...
    英勇青銅5閱讀 2,845評(píng)論 15 41
  • Activity https://developer.android.com/guide/components/a...
    XLsn0w閱讀 768評(píng)論 0 4
  • Activity 在應(yīng)用中的表現(xiàn)主要是顯示各種UI元素,并且為這些UI元素設(shè)置時(shí)間處理函數(shù),使得用用戶可以與這些U...
    sssssss_閱讀 768評(píng)論 0 1
  • Activity是一個(gè)應(yīng)用組件,用戶可與其提供的屏幕進(jìn)行交互。以執(zhí)行撥打電話,拍攝照片,發(fā)送電子郵件或查看地圖等操...
    DanieX閱讀 1,161評(píng)論 0 4
  • 該系列主要是記錄、回顧之前的學(xué)習(xí)和一些筆記。轉(zhuǎn)載請(qǐng)注明! Activity在應(yīng)用中的表現(xiàn)為界面,它會(huì)加載指定的布局...
    Angki閱讀 421評(píng)論 0 0

友情鏈接更多精彩內(nèi)容