Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android源碼適配器模式-Activity類結構

Android源碼適配器模式-Activity類結構

編輯:關於Android編程

其實適配器模式在Android源碼中非常多,而從整體的源碼角度上來看Activity的結構就是一種適配器模式。從這個角度上面看Activity,對Activity和應用層框架會有更加深入的理解。

適配器模式

意圖

將一個接口轉換為用戶需要的另外一個接口,適配器模式使得原本由於接口不兼容不能一起工作的那些類可以一起工作。

UML圖

適配器模式有兩種模式,UML分別如下:

這裡寫圖片描述
這裡寫圖片描述

第一種是直接繼承已經有的接口適配目標接口,而第二種是引用已有的接口適配目標接口。

示例代碼

interface Target{
    void request();
}

class Adaptee{
    public void specialRequest(){
        System.out.println("special from adaptee");
    }
}

class Adapter extends Adaptee implements Target{
    public void request(){
        //do something to implements request
        specialRequest();
    }
}

public static final void main(String args[]){
    Target target = new Adapter();
    target.request();
}

上面是第一種適配器模式的簡單代碼示例,通過繼承已有的類來適配,另外一種組合的方式如下:

interface Target{
    void request();
}

class Adaptee{
    public void specialRequest(){
        System.out.println("special from adaptee");
    }
}

class Adapter implements Target{
    private Adaptee adaptee ;
    public void Adapter(Adaptee adaptee){
        this.adaptee = adaptee;
    }
    public void request(){
        //do something to implements request
        adaptee.specialRequest();
    }
}

public static final void main(String args[]){
    Target target = new Adapter(new Adaptee());
    target.request();
}

兩種方式類適配器和對象適配器。

Activity與適配器模式

Activity是Android的核心組件,它是負責應用UI的組件,可以說是Android四大組件中最重要,使用最多,最復雜的組建。它的源碼也相當地龐大。從適配器的角度上來看,Activity適配了多個接口,先看一下它的類結構圖:

這裡寫圖片描述

將Activity看成是適配器模式初看可能會有點牽強。但是ContextThemeWrapper是表示主題的環境類,Context可以翻譯為應用環境,但是對於需要顯示UI的一個應用組建除了應用環境外,還需要適應其他的內容信息,比如Window,比如KeyEvent等等。

拿窗口系統舉例。Android中有Window管理系統,但是窗口系統需要與的Window.Callback接口,但是現在是有了Context,組建需要Window.Callback接口,這樣創建Activity(這個是Adapter)實現Window.Callback接口,並且繼承ContextThemeWrapper,將ContextWrapper與Window.Callback協作,讓Context與Window一起工作。Window.Callback只是Activity適配的其中一個接口,下面分別介紹類結構的每一個部分。

ContextThemeWrapper

這是一個包含主題的Context裝飾器,本身ContextWrapper是一個裝飾器模式,在Android中,四大組建都是ContextWrapper的子類,四大組建都需要應用環境。需要理解的是Context是一個應用環境類型,Context包含了各種跟應用環境相關的信息,可以用來與應用系統打交道的。

Window.Callback, Window.OnWindowDismissedCallback

Window.Callback 這個接口包含了很多接口函數,上面的UML圖中只包含了部分接口,全部的接口類可見下面的Outline截圖:

這裡寫圖片描述

這個接口是窗口的回調接口,主要分為屏幕事件觸發,按鍵事件觸發,Panel相關的View創建與Prepare,Menu的回調,Window的變化回調,SearchRequest的回調,以及ActionMode的回調。

Window.OnWindowDismissedCallback是一個hide類,是無法通過API調用的,是當窗口消失(Window系統移除)的時候的回調接口。Activity的實現也很簡單,直接finish掉自己。

/**
 * Called when the main window associated with the activity has been dismissed.
 * @hide
 */
@Override
public void onWindowDismissed() {
    finish();
}

Callback,OnWindowDismissedCallback是Window與Activity交互的回調接口。

初始部分代碼為:

//Activity.java
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        ...

但實際上一個Window並不是只和一個Activity關聯,而是一個Window和一個Callback關聯,Activity也是Context,Android中Dialog裡面也包含了Window,Dialog也實現了Callback接口。一個應用環境中(Context)可能包含多個Window,也就會有多個Callback,只是Activity這種應用環境本身就實現了Callback接口。

KeyEvent.Callback

對應著Key事件的回調接口,當按下按鍵的時候,會回調該接口。主要是為了適配輸入系統。

ComponentCallbacks2

它是ComponentCallbacks的子接口,CompoentCallbacks包含下面兩個接口:

void onConfigurationChanged(Configuration newConfig);

void onLowMemory();

ComponentCallbacks2新增了onTrimMemory接口。
ComponentCallbacks是專門為Android組件使用的回調接口,Android組件都會實現該接口(目前變成了ConponentCallbacks2),當配置信息變化,內存變化的時候,這些接口會被調用。調用這些接口的是ActivityThread(消息循環中,收到變化消息時),ViewRootImpl(在Window有變化的時候,ViewRootImpl負責與WindowManagerService通信)等。該接口是為了適配系統信息管理部分。

這裡有兩個跟內存相關的接口,這其實是為幫應用應對Android內存滿負荷,提醒應用程序做一些釋放內存處理,如果占用內存過大,應用將會更容易被殺死。具體可以看LowMemoryKiller的介紹。

OnCreateContextMenuListener

Android上下文菜單: 當給一個View注冊了上下文菜單後,對這個View長按2秒,會彈出一個浮動的菜單。OnCreateContextMenuListener 它只有一個接口函數:

public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    }

當View的Context menu被創建的時候,該接口的會被調用,用於獲取Menu(作為實現改接口的Activity來講,是設置Menu)。在Activity中,與這個接口函數對應的函數是onContextItemSelected,而該函數是繼承自Window.Callback接口的onMenuItemSelected函數:

    public boolean onMenuItemSelected(int featureId, MenuItem item) {
        CharSequence titleCondensed = item.getTitleCondensed();

        switch (featureId) {
            case Window.FEATURE_OPTIONS_PANEL:
                if(titleCondensed != null) {
                        EventLog.writeEvent(50000, 0, titleCondensed.toString());
                }
                if (onOptionsItemSelected(item)) {
                    return true;
                }
            ...
            case Window.FEATURE_CONTEXT_MENU:
                if(titleCondensed != null) {
                    EventLog.writeEvent(50000, 1, titleCondensed.toString());
                }
                if (onContextItemSelected(item)) { //這裡
                    return true;
                }
                return mFragments.dispatchContextItemSelected(item);

            default:
                return false;
        }
    }

我們平時監聽普通的Menu的函數onOptionsItemSelected也是由onMenuItemSelected調用的。

另外一邊View中顯示ContextMenu的函數是showContextMenu:

public boolean showContextMenu() {
    return getParent().showContextMenuForChild(this);
}

ViewGroup的showContextMenuForChild為:

public boolean showContextMenuForChild(View originalView) {
    return mParent != null && mParent.showContextMenuForChild(originalView);
}

getParent()最終會到DecorView,DecorView中創建了ContextMenu。然後調用View的createContextMenu方法,最終使用mOnCreateContextMenuListener獲取Menu:

public void createContextMenu(ContextMenu menu) {
    ContextMenuInfo menuInfo = getContextMenuInfo();

    // Sets the current menu info so all items added to menu will have
    // my extra info set.
    ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo);

    onCreateContextMenu(menu);
    ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnCreateContextMenuListener != null) {
        li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo);
    }

    // Clear the extra information so subsequent items that aren't mine don't
    // have my extra info.
    ((MenuBuilder)menu).setCurrentMenuInfo(null);

    if (mParent != null) {
        mParent.createContextMenu(menu);
    }
}

DecorView在PhoneWindow中,Menu其實會由Window統一管理,響應Item的點擊事件的接口是一致的(Window.Callback.onMenuItemSelected),另外ContextMenu實際上顯示出來的就是一個Dialog。但由於ContextMenu是跟View對應的,所以有了OnCreateContextMenuListener接口,它是用於當View需要創建ContextMenu的時候,方便指定ContextMenu的內容。

LayoutInflater.Factory2

這個接口只有一個接口函數:

public View onCreateView(View parent, String name, Context context, AttributeSet attrs);

它繼承自Factory:

   public interface Factory {
        /**
         * Hook you can supply that is called when inflating from a LayoutInflater.
         * You can use this to customize the tag names available in your XML
         * layout files.
         * 
         * 

* Note that it is good practice to prefix these custom names with your * package (i.e., com.coolcompany.apps) to avoid conflicts with system * names. */ public View onCreateView(String name, Context context, AttributeSet attrs); }

用於跟LayoutInflater系統交互,為了適配LayoutInflater系統。實現改接口,可以在Inflater的時候,解析XML中自定義的Tag。該接口為LayoutInflater調用,而LayoutInflater的實現為PhoneLayoutInflater。

除了Activity外,Application和Service都實現了ComponnentCallbacks接口,繼承了ContextWrapper,其實都可以用類適配器模式看待。

設計思考

本身應用組件都應該是一種應用環境(Context),但是又需要滿足Window等系統的回調需求,我們平時可能直接單獨實現Window.Callback接口,但是將Activity實現Window.Callback接口,那麼Activity會更加具有整體性,不過設計意圖在這裡思考過多感覺有點太牽強。

總結

從Android應用層源碼整理來看,Activity的類結構完全可以看成是一種適配器模式,在基於應用環境(Context)的情況下,去滿足LayoutInflater系統(LayoutInflater.Factory2),Window系統(Window.Callback,Window.OnWindowDismissedCallback),輸入系統(KeyEvent.Callback)的接口需求,另外ComponnentCallbacks更是ActivityThread和ViewRootImpl需要的接口。通過適配器模式來看Activity,對於Activity,對於Activity與其他部分的交互,對於應用層框架會有更好的理解。另外再有裝飾模式看Context,對於整個應用層結構會更清晰。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved