1. 程式人生 > >Theme類、程序的分類、SimpleAdapter類、ANR和FC

Theme類、程序的分類、SimpleAdapter類、ANR和FC

Android中Theme類可以繼承?

不可以

解析:我們先看一下AndroidManifest.xml檔案,裡面有這麼一行程式碼

android:theme="@style/AppTheme"

即對主題樣式的指定、設定,接下來進入styles.xml檔案

    <style name="AppTheme1" parent="Theme.AppCompat.Light">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    <style name="Animation" />
    <style name="Animation.Dialog">
        <item name="windowEnterAnimation">@anim/dialog_enter</item>
        <item name="windowExitAnimation">@anim/dialog_exit</item>
    </style>

這裡的樣式程式碼,可以分為兩種,一種是使用parent,代表該樣式來自哪裡?一般在java裡,我們都說繼承,parent即對應父類,另一種是使用已有的style名字後直接加.來表示(這種是自定義的style),這麼看來,似乎Theme類是可以繼承的,我就是這樣認識錯的。下面我們再從用程式碼設定主題的方面來看一下,

直接在activity裡就可以設定setTheme(); 我們點進去

    @Override
    public void setTheme(@StyleRes final int resid) {
        super.setTheme(resid);
        // Keep hold of the theme id so that we can re-set it later if needed
        mThemeId = resid;
    }

我們來看一下這個mThemeId是如何使用的(只看重點,感興趣自己看原始碼)

if (Build.VERSION.SDK_INT >= 23) {
                onApplyThemeResource(getTheme(), mThemeId, false);
            } else {
                setTheme(mThemeId);
            }

這裡就對6.0上下進行了不同的方法設定,我們先看6.0以上的系統

    @Override
    protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid,
            boolean first) {
        if (mParent == null) {
            super.onApplyThemeResource(theme, resid, first);
        } else {
            try {
                theme.setTo(mParent.getTheme());
            } catch (Exception e) {
                // Empty
            }
            theme.applyStyle(resid, false);
        }

        // Get the primary color and update the TaskDescription for this activity
        TypedArray a = theme.obtainStyledAttributes(
                com.android.internal.R.styleable.ActivityTaskDescription);
        if (mTaskDescription.getPrimaryColor() == 0) {
            int colorPrimary = a.getColor(
                    com.android.internal.R.styleable.ActivityTaskDescription_colorPrimary, 0);
            if (colorPrimary != 0 && Color.alpha(colorPrimary) == 0xFF) {
                mTaskDescription.setPrimaryColor(colorPrimary);
            }
        }

        int colorBackground = a.getColor(
                com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
        if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
            mTaskDescription.setBackgroundColor(colorBackground);
        }

        final int statusBarColor = a.getColor(
                com.android.internal.R.styleable.ActivityTaskDescription_statusBarColor, 0);
        if (statusBarColor != 0) {
            mTaskDescription.setStatusBarColor(statusBarColor);
        }

        final int navigationBarColor = a.getColor(
                com.android.internal.R.styleable.ActivityTaskDescription_navigationBarColor, 0);
        if (navigationBarColor != 0) {
            mTaskDescription.setNavigationBarColor(navigationBarColor);
        }

        a.recycle();
        setTaskDescription(mTaskDescription);
    }

這裡面看著是否和自定義view有點相似,大概就是一層層摳出來,像我們前面寫的style有parent,點到為止,這裡不是研究這個問題。6.0以下的,就直接看他的父類方法

    @Override
    public void setTheme(int resid) {
        if (mThemeResource != resid) {
            mThemeResource = resid;
            initializeTheme();
        }
    }

發現,mThemeResource的使用和6.0以上類似(不做重點),繼續initializeTheme(初始化主題)

    private void initializeTheme() {
        final boolean first = mTheme == null;
        if (first) {
            mTheme = getResources().newTheme();
            final Resources.Theme theme = getBaseContext().getTheme();
            if (theme != null) {
                mTheme.setTo(theme);
            }
        }
        onApplyThemeResource(mTheme, mThemeResource, first);
    }

重點出現了,Theme是用final修飾的,很明顯不能被繼承。

程序的分類

前臺程序

使用者當前操作所必需的程序。如果一個程序滿足以下任一條件,即視為前臺程序:

託管使用者正在互動的 Activity(已呼叫 Activity 的 onResume() 方法)
託管某個 Service,後者繫結到使用者正在互動的 Activity
託管正在“前臺”執行的 Service(服務已呼叫 startForeground())
託管正執行一個生命週期回撥的 Service(onCreate()、onStart() 或 onDestroy())
託管正執行其 onReceive() 方法的 BroadcastReceiver
通常,在任意給定時間前臺程序都為數不多。只有在記憶體不足以支援它們同時繼續執行這一萬不得已的情況下,系統才會終止它們。 此時,裝置往往已達到記憶體分頁狀態,因此需要終止一些前臺程序來確保使用者介面正常響應。

可見程序

沒有任何前臺元件、但仍會影響使用者在螢幕上所見內容的程序。 如果一個程序滿足以下任一條件,即視為可見程序:

託管不在前臺、但仍對使用者可見的 Activity(已呼叫其 onPause() 方法)。例如,如果前臺 Activity 啟動了一個對話方塊,允許在其後顯示上一 Activity,則有可能會發生這種情況。
託管繫結到可見(或前臺)Activity 的 Service。
可見程序被視為是極其重要的程序,除非為了維持所有前臺程序同時執行而必須終止,否則系統不會終止這些程序。

服務程序

正在執行已使用 startService() 方法啟動的服務且不屬於上述兩個更高類別程序的程序。儘管服務程序與使用者所見內容沒有直接關聯,但是它們通常在執行一些使用者關心的操作(例如,在後臺播放音樂或從網路下載資料)。因此,除非記憶體不足以維持所有前臺程序和可見程序同時執行,否則系統會讓服務程序保持執行狀態。

後臺程序

包含目前對使用者不可見的 Activity 的程序(已呼叫 Activity 的 onStop() 方法)。這些程序對使用者體驗沒有直接影響,系統可能隨時終止它們,以回收記憶體供前臺程序、可見程序或服務程序使用。 通常會有很多後臺程序在執行,因此它們會儲存在 LRU (最近最少使用)列表中,以確保包含使用者最近檢視的 Activity 的程序最後一個被終止。如果某個 Activity 正確實現了生命週期方法,並儲存了其當前狀態,則終止其程序不會對使用者體驗產生明顯影響,因為當用戶導航回該 Activity 時,Activity 會恢復其所有可見狀態。 有關儲存和恢復狀態的資訊,請參閱 Activity文件。

空程序

不含任何活動應用元件的程序。保留這種程序的的唯一目的是用作快取,以縮短下次在其中執行元件所需的啟動時間。 為使總體系統資源在程序快取和底層核心快取之間保持平衡,系統往往會終止這些程序。

SimpleAdapter類支援的繫結view型別

if (!bound) {
                    //該view是否實現checkable介面
                    if (v instanceof Checkable) {
                        if (data instanceof Boolean) {
                            ((Checkable) v).setChecked((Boolean) data);
                        //該view是否是TextView
                        } else if (v instanceof TextView) {
                            // Note: keep the instanceof TextView check at the bottom of these
                            // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                            setViewText((TextView) v, text);
                        } else {
                            throw new IllegalStateException(v.getClass().getName() +
                                    " should be bound to a Boolean, not a " +
                                    (data == null ? "<unknown type>" : data.getClass()));
                        }
                    } else if (v instanceof TextView) {
                        // Note: keep the instanceof TextView check at the bottom of these
                        // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                        setViewText((TextView) v, text);
                    //該view是否是ImageView
                    } else if (v instanceof ImageView) {
                        if (data instanceof Integer) {
                            setViewImage((ImageView) v, (Integer) data);
                        } else {
                            setViewImage((ImageView) v, text);
                        }
                    } else {
                        throw new IllegalStateException(v.getClass().getName() + " is not a " +
                                " view that can be bounds by this SimpleAdapter");
                    }
                }

以上原始碼很明顯能看出來使用SimpleAdapter作為介面卡時,支援三種類型的 View,而且是按照如下順序進行匹配: 實現Checkable介面 、TextView、 ImageView,但面試或筆試的時候,問你的不一定是這麼明顯,比如CompoundButton是否支援?它支援是因為它實現了checkable介面還是TextView的子類?因為這是按照順序判斷的,所以CompoundButton實現了Checkable介面,所以被SimpleAdapter支援,雖然它同樣可以在第二個判斷裡通過,但不考慮。

ANR和FC

ANR(Application Not Respone):程式無響應,有可能程式會再次響應

出現條件:1.當用戶輸入事件5s內沒有得到響應,將彈出ANR對話方塊  2.廣播接收者的onReceive()執行時間超過10s

FC(Force close):程式丟擲異常,會強制退出

出現條件:Error 、OOM,記憶體溢位 、StackOverFlowError 、Runtime,比如說空指標異常

關於這兩種情況如何避免,以後再說,這裡主要是要說下正確理解和區分這兩種情況。