Android設計模式--觀察者模式

來源:互聯網
上載者:User

標籤:android   設計模式   

問題:

在Android中,根據Android的事件樹,我們知道:在與螢幕按鍵、觸摸、滑動等操作與應用進行互動時觸發的相關事件中,互動事件是沿著事件樹自頂向下傳播的;

當位於事件樹上層的父控制項接受到事件後,判斷事件的所屬,若需要,則截獲事件,否則,向下子控制項傳播。


那麼我們在編寫各種Listener,在View各種事件函數接受和處理各類互動事件,這種處理模式,是否就是一種觀察者模式呢?


問題,先放於此處。

言歸正傳:

觀察者模式:


1、定義:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents aer notified and updated automatically. 
定義對象間一種一對多的依賴關係,使得當一個對象改變狀態,則所有依賴於它的對象都會得到通知並被自動更新。


2、適用:
當一個對象的改變需要同時改變其他對象的時候,並且他不知道有多少對象需要改變的時候,考慮使用觀察者模式;


3、目的:

觀察者模式所做的工作其實就是在解耦合,讓耦合的雙方都依賴與抽象,而不依賴於具體使得雙方的變化都不影響另一方的變化;


4、原則:

觀察者模式符合依賴倒轉原則;


5、其他:

觀察者模式是一種對象的行為模式,又叫發布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。


6、簡單的demo:

demo 的業務是:一個按鈕對象,當按鈕點擊時,通知兩個視圖的改變;

首先是:觀察者:

package com.example.demo.Observer;/** * 抽象觀察者(Observer)角色 * @author qubian * @data 2015年6月11日 * @email [email protected] * */public interface Observer {public void upadteView(String info);}package com.example.demo.Observer;import android.util.Log;/** * 具體觀察者角色 * @author qubian * @data 2015年6月11日 * @email [email protected] * */public class Observer_View1 implements Observer{@Overridepublic void upadteView(String info) {Log.i("upadteView", "Observer_View1,視圖1發生變化,變化的內容是:"+info);}}package com.example.demo.Observer;import android.util.Log;/** * 具體觀察者角色 * @author qubian * @data 2015年6月11日 * @email [email protected] * */public class Observer_View2  implements Observer{@Overridepublic void upadteView(String info) {Log.i("upadteView", "Observer_View2,視圖2發生變化,變化的內容是:"+info);}}

主題角色:

package com.example.demo.Observer;import java.util.ArrayList;import java.util.List;/** * 抽象主題(Subject)角色 * @author qubian * @data 2015年6月11日 * @email [email protected] * */public abstract class Subject {private List<Observer> list;/** * 添加觀察者,面向介面,面向抽象編程 * @param observer */public void  addObserver(Observer observer){if (list==null) {list = new ArrayList<Observer>();}list.add(observer);}/** * 通知視圖改變 * @param info */public void notifyDataSetChange(String info){for (Observer observer : list) {observer.upadteView(info);}}}package com.example.demo.Observer;import android.util.Log;/** * 具體被觀察者角色 * 比如說我,點擊了按鈕,我希望,視圖發生變化 * @author qubian * @data 2015年6月11日 * @email [email protected] * */public class Subject_Button extends Subject{/** * 點擊了按鈕,我希望,視圖發生變化 */public void Click(){Log.i("Subject_Button", "點擊了按鈕");String tag ="101";notifyDataSetChange(tag);}}

使用:

package com.example.demo.Observer;/** *  使用 * @author qubian * @data 2015年6月11日 * @email [email protected] * */public class UseObserver {public void use(){// 業務是這樣的:我,點擊了按鈕,我希望綁定在這個按鈕上的視圖發生變化// 首先 是有兩個視圖的觀察者:Observer  obj1 = new Observer_View1();Observer  obj2 = new Observer_View2();// 按鈕Subject_Button sub = new Subject_Button();sub.addObserver(obj1);sub.addObserver(obj2);// 點擊按鈕 視圖變化sub.Click();}}

7、java庫:

在java中的java.util庫裡面,提供了一個Observable類以及一個Observer介面,構成java語言對觀察者模式的支援。

使用比較簡單,具體觀察對象實現Observer介面,被觀察者繼承Observable類,即可。

比較簡單,不再說明了;

/* *  Licensed to the Apache Software Foundation (ASF) under one or more *  contributor license agreements.  See the NOTICE file distributed with *  this work for additional information regarding copyright ownership. *  The ASF licenses this file to You under the Apache License, Version 2.0 *  (the "License"); you may not use this file except in compliance with *  the License.  You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * *  Unless required by applicable law or agreed to in writing, software *  distributed under the License is distributed on an "AS IS" BASIS, *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *  See the License for the specific language governing permissions and *  limitations under the License. */package java.util;/** * {@code Observer} is the interface to be implemented by objects that * receive notification of updates on an {@code Observable} object. * * @see Observable */public interface Observer {    /**     * This method is called if the specified {@code Observable} object's     * {@code notifyObservers} method is called (because the {@code Observable}     * object has been updated.     *     * @param observable     *            the {@link Observable} object.     * @param data     *            the data passed to {@link Observable#notifyObservers(Object)}.     */    void update(Observable observable, Object data);}package android.database;import java.util.ArrayList;/** * Provides methods for registering or unregistering arbitrary observers in an {@link ArrayList}. * * This abstract class is intended to be subclassed and specialized to maintain * a registry of observers of specific types and dispatch notifications to them. * * @param T The observer type. */public abstract class Observable<T> {    /**     * The list of observers.  An observer can be in the list at most     * once and will never be null.     */    protected final ArrayList<T> mObservers = new ArrayList<T>();    /**     * Adds an observer to the list. The observer cannot be null and it must not already     * be registered.     * @param observer the observer to register     * @throws IllegalArgumentException the observer is null     * @throws IllegalStateException the observer is already registered     */    public void registerObserver(T observer) {        if (observer == null) {            throw new IllegalArgumentException("The observer is null.");        }        synchronized(mObservers) {            if (mObservers.contains(observer)) {                throw new IllegalStateException("Observer " + observer + " is already registered.");            }            mObservers.add(observer);        }    }    /**     * Removes a previously registered observer. The observer must not be null and it     * must already have been registered.     * @param observer the observer to unregister     * @throws IllegalArgumentException the observer is null     * @throws IllegalStateException the observer is not yet registered     */    public void unregisterObserver(T observer) {        if (observer == null) {            throw new IllegalArgumentException("The observer is null.");        }        synchronized(mObservers) {            int index = mObservers.indexOf(observer);            if (index == -1) {                throw new IllegalStateException("Observer " + observer + " was not registered.");            }            mObservers.remove(index);        }    }    /**     * Remove all registered observers.     */    public void unregisterAll() {        synchronized(mObservers) {            mObservers.clear();        }    }}

8、android的運用:

迴歸到,上面的問題;

很明顯,上述的Android事件樹的傳遞,互動事件的監聽,我們所寫的Listener回調,整個監聽部分就是一種觀察者模式。


在我們最熟悉的點擊事件中,初始化時,我們設定視圖的監聽:


    /**     * Register a callback to be invoked when this view is clicked. If this view is not     * clickable, it becomes clickable.     *     * @param l The callback that will run     *     * @see #setClickable(boolean)     */    public void setOnClickListener(OnClickListener l) {        if (!isClickable()) {            setClickable(true);        }        getListenerInfo().mOnClickListener = l;    }

OnClickListener介面的描述:

    /**     * Interface definition for a callback to be invoked when a view is clicked.     */    public interface OnClickListener {        /**         * Called when a view has been clicked.         *         * @param v The view that was clicked.         */        void onClick(View v);    }

OnclickListener 是在View 視圖內部類ListenerInfo中:

static class ListenerInfo {        protected OnFocusChangeListener mOnFocusChangeListener;        private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;        private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;        /**         * Listener used to dispatch click events.         * This field should be made private, so it is hidden from the SDK.         * {@hide}         */        public OnClickListener mOnClickListener;        protected OnLongClickListener mOnLongClickListener;        protected OnCreateContextMenuListener mOnCreateContextMenuListener;        private OnKeyListener mOnKeyListener;        private OnTouchListener mOnTouchListener;        private OnHoverListener mOnHoverListener;        private OnGenericMotionListener mOnGenericMotionListener;        private OnDragListener mOnDragListener;        private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;    }

調用:

    public boolean performClick() {        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);        ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            playSoundEffect(SoundEffectConstants.CLICK);            li.mOnClickListener.onClick(this);            return true;        }        return false;    }    public boolean callOnClick() {        ListenerInfo li = mListenerInfo;        if (li != null && li.mOnClickListener != null) {            li.mOnClickListener.onClick(this);            return true;        }        return false;    }

至於PerformClick的調用,則是在視圖的監聽OnTouchEvent等有具體的體現:

 public boolean onTouchEvent(MotionEvent event) {        if (((viewFlags & CLICKABLE) == CLICKABLE ||                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {            switch (event.getAction()) {                case MotionEvent.ACTION_UP:                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {                        // take focus if we don't have it already and we should in                        // touch mode.                        boolean focusTaken = false;                        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {                            focusTaken = requestFocus();                        }                        if (prepressed) {                            // The button is being released before we actually                            // showed it as pressed.  Make it show the pressed                            // state now (before scheduling the click) to ensure                            // the user sees it.                            setPressed(true);                       }                        if (!mHasPerformedLongPress) {                            // This is a tap, so remove the longpress check                            removeLongPressCallback();                            // Only perform take click actions if we were in the pressed state                            if (!focusTaken) {                                // Use a Runnable and post this rather than calling                                // performClick directly. This lets other visual state                                // of the view update before click actions start.                                if (mPerformClick == null) {                                    mPerformClick = new PerformClick();                                }                                if (!post(mPerformClick)) {                                    performClick();                                }                            }                        }                        if (mUnsetPressedState == null) {                            mUnsetPressedState = new UnsetPressedState();                        }                        if (prepressed) {                            postDelayed(mUnsetPressedState,                                    ViewConfiguration.getPressedStateDuration());                        } else if (!post(mUnsetPressedState)) {                            // If the post failed, unpress right now                            mUnsetPressedState.run();                        }                        removeTapCallback();                    }                    break;                case MotionEvent.ACTION_DOWN:                                       break;                case MotionEvent.ACTION_CANCEL:                                   case MotionEvent.ACTION_MOVE:                                       break;            }            return true;        }        return false;    }


Android設計模式--觀察者模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.