1. 程式人生 > >Android 6.0 執行中手動去設定介面取消該app的某個許可權,導致application被強制銷燬造成app崩潰問題的解決

Android 6.0 執行中手動去設定介面取消該app的某個許可權,導致application被強制銷燬造成app崩潰問題的解決

android 6.0版本已經發布了很長時間了,相信大家都知道6.0 系統加入了執行時許可權管理,一些危險許可權需要在執行時申請。

現在有這麼一種情況,如果在一開始使用者授予了某項許可權,比如定位許可權或者相機許可權,當應用程式已經啟動了,使用者手動按下主鍵之後,回到桌面,開啟設定,進入該應用程式的許可權管理介面,對該應用程式的許可權進行手動取消和給與許可權,這時候應用就會莫名其妙的重啟,且不會執行activity 和 fragment的生命週期函式,但實質應用已經掛掉了,很奇怪的是app不會被crash掉,且沒有任何日誌。
如果專案中使用到了Fragment,再次點選應用圖示將app從後臺喚醒,會出現app崩潰提示,大概就是以下異常:

     java.lang.IllegalStateException: Fragment does not have a view
    at android.support.v4.app.Fragment$1.onFindViewById(Fragment.java:1933)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1057)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java
:1252) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1234) at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2046) at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1989) at android.support
.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1092) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1234) at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2046) at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:174) at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:598) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1238) at android.app.Activity.performStart(Activity.java:6320) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2386) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2483) at android.app.ActivityThread.access$900(ActivityThread.java:153) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1349) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5441) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
這種情況是因為在許可權設定介面取消或者取消後再重新手動給予該許可權,再次進入該app時,裡面的資料和物件已經被回收了但是有沒有崩潰,介面還在。
這個問題該如何解決呢?  
在activity中重寫 
@Override
protected void onSaveInstanceState(Bundle outState) {
// super.onSaveInstanceState(outState);
} 
方法中註釋掉
    super.onSaveInstanceState(outState);

很好理解,在application被銷燬後,系統要回收Fragment時,我們告訴系統:不要再儲存Fragment。如此就解決了將app從後臺喚醒,app出現該異常的問題。

重點:
但是這是一種取巧的方式,原因是什麼呢,我這個android開發框架,在使用Fragment時使用建構函式傳遞引數,當Fragment被重建時,預設走無參建構函式,導致出現該異常。

所以在Fragment的基類裡建立一個抽象函式

protected abstract int getLayout();

並在onCreatView裡呼叫:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        View v = inflater.inflate(getLayout(), null);
        return v;
        }

每一個Fragment都繼承該基類,並實現getLayout()方法,設定佈局ID。具體為:

    @Override
    protected int getLayout() {
        return R.layout.fm_home;
    }

另外向Fragment使用setArguments()+Bundle傳參,注意在Fragment裡接收引數時對getArguments()進行判空,防止空指標異常的出現。