第三篇 android 應用開發模式之MVC模式及Observer模式

來源:互聯網
上載者:User

如果說模板模式是ANDROID架構的核心,提供了應用程式架構組件的基礎,而Observer模式則提供了ANDROD架構串連件的基礎,同時也是另外兩個組件廣播組件及內容提供者組件的實現基礎,還是UI輸入機制的基礎。Observer模式在android應用程式及架構中普遍採用。

Observer模式也稱作發布/訂閱模式,實現機理是訊息發布/訂閱模式的事件驅動模型:訊息的生產者發布事件,而使用者訂閱感興趣的事件。

我們知道Observer模式是MVC模式的基礎,而 MVC模式是ANDROID架構隱藏的一個重要模式。在ANDROID架構看來ACTIVITY連同其基類ContextImpl擔負著MVC模式中的控制器(Controller)角色,用來轉寄視圖發送的控制請求,並和模型(Model)互動;而ACTIVITY綁定的視圖(DecorView),在MVC模式中也起到視圖(VIEW)角色,DecorView是ACTIVITY的主視圖,其它子視圖或控制項都由ACTIVITY通過讀取應用程式的布局檔案(XML格式)產生,並組合成視圖樹,實現視圖的布局(視圖採用了組合模式組合成視圖樹)。而架構的每一個服務及其產生的資料則提供了MVC模型(Model)的角色。而每個服務通過ContextImpl中登記的本地服務管理對象進行控制,視圖也通過控制器(ContextImpl)登記對模型事件的監聽,控制器本身也可以登記為監聽對象。本地服務管理對象本身或者應用程式視圖通過本地服務管理對象(Controller)向模型發出請求訊息和服務(Model)互動,服務產生的資料發生變化時,通過Observer模式(廣播或INTENT)通知視圖和控制器。在MVC模式中視圖是觀察者Observer,視圖通過組合模式組合成視圖樹,控制器擔當視圖和模型的中介者,因此這裡的MVC模式是採用Observer模式、組合模式、中介模式的複合模式。

採用MVC模式可以簡化應用程式的開發,而通過架構提供模型及控制器的實現則使應用程式的開發更加容易。應用程式只需繼承控制器(ACTIVITY)和實現回調介面、編寫VIEW的布局XML檔案、提供用到的資源檔、註冊對模型的監聽事件、編寫與模型提供資料的介面(ANDROID又是推薦採用Adapter模式實現與各種資料來源介面,ANDROID為此針對資料庫提供了SimpleCursorAdapter類)等五個任務就可完成應用程式的開發。而商務邏輯及資料提供、轉寄視圖的控制請求都交給架構處理好了,應用開發如此簡單。下面看一個ACTIVITY的具體例子。

    private BroadcastReceiver mScanListener = new BroadcastReceiver() {//執行個體化一個廣播對象

        @Override

        public void onReceive(Context context, Intent intent) {//實現廣播接收回調介面

            MusicUtils.setSpinnerState(AlbumBrowserActivity.this);

            mReScanHandler.sendEmptyMessage(0);

            if (intent.getAction().equals(Intent.ACTION_MEDIA_UNMOUNTED)) {

                MusicUtils.clearAlbumArtCache();

            }

        }

    };

public class  MyActivity extends Activity implements OnItemClickListener {

    @Override

       protected void onCreate(Bundle savedInstanceState) {

 super.onCreate(savedInstanceState);

       IntentFilter f = new IntentFilter();

        f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);

        f.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);

        f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);

        f.addDataScheme("file");

        registerReceiver(mScanListener, f);//註冊對模型的廣播監聽事件

        setContentView(R.layout.media_picker_activity);//讀取布局檔案產生視圖樹

 Cursor c = getContentResolver().query(Settings.System.CONTENT_URI, null, null, null, null);

//首先通過控制器獲得資料來源的指標

 ListAdapter adapter = new SimpleCursorAdapter(this,

               android.R.layout.simple_list_item_1,

                  c,

                new String[] {People.NAME} ,

                new int[] {android.R.id.text1});

 setListAdapter(adapter);//採用Adapter模式設定與資料來源的介面

 getListView().setOnItemClickListener(this);//設定視圖控制項的監聽者,控制器監聽

    }

    public void onItemClick(AdapterView parent, View view, int position, long id) {//視圖監聽事件的回調介面

        Intent dummyIntent = new Intent(this, ListSimple.class);

        startActivity(dummyIntent);

}

在ContextImpl中採用靜態代碼塊的方法把總共34個系統服務管理對象預先登記到ContextImpl的CACHE中,視圖或控制器對象通過getSystemService介面統一從cache擷取服務管理對象,實現與模型的互動。由於這種方式實現了對象只在封裝載時執行個體化一次,並登記到cache,因此能夠實現提高擷取系統服務管理對象的速度的目的。

    private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =

            new HashMap<String, ServiceFetcher>();//執行個體化儲存fetcher對象的HashMap,fetcher對象實際完成讀取本地服務管理對象的目的。

 private static void registerService(String serviceName, ServiceFetcher fetcher) {

        if (!(fetcher instanceof StaticServiceFetcher)) {

            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;

        }

        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);//根據服務名字把fetcher對象放到HashMap中

    }

    static {

        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {

                public Object getService(ContextImpl ctx) {

                    return AccessibilityManager.getInstance(ctx);

                }});//把一個fetcher對象登記到ACCESSIBILITY_SERVICE服務名字對應的HashMap中,並覆蓋getService函數

 

        registerService(ACCOUNT_SERVICE, new ServiceFetcher() {

                public Object createService(ContextImpl ctx) {

                    IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);

                    IAccountManager service = IAccountManager.Stub.asInterface(b);

                    return new AccountManager(ctx, service);

                }});//把一個fetcher對象登記到ACCOUNT_SERVICE服務名字對應的HashMap中,並實現其createService介面。 

 

}

 static class ServiceFetcher {

public Object getService(ContextImpl ctx) {

            ArrayList<Object> cache = ctx.mServiceCache;

            Object service;

            synchronized (cache) {

                if (cache.size() == 0) {

                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {

                        cache.add(null);

                    }

                } else {

                    service = cache.get(mContextCacheIndex);//從cache中擷取服務

                    if (service != null) {

                        return service;

                    }

                }

                service = createService(ctx);// 在cache中擷取不到則執行個體化服務管理對象。

                cache.set(mContextCacheIndex, service);//重新把新建立的服務管理對象放到cache中,供下次使用。

                return service;

            }

        }

}

    @Override

    public Object getSystemService(String name) {//擷取本地服務管理對象統一介面

        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);

        return fetcher == null ? null : fetcher.getService(this);//通過fetcher的getService介面擷取本地服務管理對象。

    }

架構中Observer模式大量採用,包括JNI向JAVA層發送通知等。見android_media_MediaPlayer.cpp檔案

 

static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)

{

    LOGV("native_setup");

    sp<MediaPlayer> mp = new MediaPlayer();

   sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);

    mp->setListener(listener);// 登記C++層媒體播放器的監聽器為一個JNI對象。

}

void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)

{

    JNIEnv *env = AndroidRuntime::getJNIEnv();

    if (obj && obj->dataSize() > 0) {

            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,

                    msg, ext1, ext2, jArray);//在這裡JNI監聽器對象轉寄播放器產生的事件

    }

}

void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)

{

    sp<MediaPlayerListener> listener = mListener;

    if ((listener != 0) && send) {

        listener->notify(msg, ext1, ext2, obj); //播放器產生事件的回調介面在這裡向JNI  listener對象發送通知。

        LOGV("back from callback");

    }

}

 

                                                                  歡迎轉載,轉載時請尊重原創註明出處。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.