본문 바로가기
Android

[Android] 안드로이드에서의 Observer

by GGoris 2014. 12. 13.
반응형

안드로이드에서의 Observer



출처   : 하이언님의 블로그 - 개발이하고싶어요

     옵저버 패턴(Observer Pattern)(1/3) - java.util.Observable

출처2 : StackOverFlow - Equivalent of iOS NSNotificationCenter in Android?



글빨이 딸립니다.

이해한데로 센서와 화면이라는 말로 쉽게 설명하려 했습니다.

잘못이해한 부분이나 잘못 설명된 부분도 있을겁니다.

댓글로 따듯한 지적 부탁드립니다.




하나의 클래스에서 변화를 인식하고, 그에 대응하는 다른 클래스의 메서드를 실행하기위해 옵저버 패턴을 사용하게 된다.


변화를 인식할 클래스에 Observable을 구현하고,  (쉽게 센서)

그 변화에 따른 메서드를 수행할 클래스에 Observer를 구현한다.   (쉽게 화면)


(단순히, 센서의 변화값을 감지해서 화면에서 표시)


stackoverflow에서 찾은 아래의 ObservingService는 변화를 인식할 즉, Obesrvable을 관리(?)하는 클래스이며, 여러 Observalbe들 중 하나는 여러개의 Observer(반응할 클래스)를 갖을 수 있다.


public class ObservingService {

    HashMap<String, Observable> observables;


    public ObservingService() {

        observables = new HashMap<String, Observable>();

    }


    public void addObserver(String notification, Observer observer) {

        Observable observable = observables.get(notification);

        if (observable==null) {

            observable = new Observable();

            observables.put(notification, observable);

        }

        observable.addObserver(observer);

    }


    public void removeObserver(String notification, Observer observer) {

        Observable observable = observables.get(notification);

        if (observable!=null) {         

            observable.deleteObserver(observer);

        }

    }       


    public void postNotification(String notification, Object object) {

        Observable observable = observables.get(notification);

        if (observable!=null) {

            observable.setChanged();

            observable.notifyObservers(object);

        }

    }



소스를 풀어 봅시다.

1.

    HashMap<String, Observable> observables;


observables 객체는 HashMap의 형태로 쉽게 말해 센서들에 이름을 붙여 구분할 수 있도록 하는 테이블이다.

String 은 센서의 이르므이 될것이고, Observable은 센서가 될 것입니다.

예를들어

   온도계,  thermometer

   습도계, hygrometer

와 같이 맵핑 되겠죠.



2.

    public void addObserver(String notification, Observer observer) {


addObserver클래스는 HashMap에 Observable을 이름(notification)과 함께 매핑시키고, 그 Observable에 반응할 Observer를 Observable에 등록시킵니다.



3. 

    Observable observable = observables.get(notification);


HashMap에서 observable(센서) 이름(notification)을 검색 한다 보시면 됩니다.

기존에 있었으면 해당 Observable을 Return할 것이고, 없었다면 null을 Return하겠죠.



4.

    if (observable==null) {

            observable = new Observable();

            observables.put(notification, observable);

    }


null인 경우 즉, 새로 등록해야하는 경우는 HashMap에 이름과 함께 매핑시키고,



5.

    observable.addObserver(observer);


해당 센서에  반응할 옵저버(화면)을 등록 시킵니다.



6.

    public void removeObserver(String notification, Observer observer) {

        Observable observable = observables.get(notification);

        if (observable!=null) {         

            observable.deleteObserver(observer);

        }

    }


삭제하는 부분은 쉽게 이해 하시리라 생각하고, 넘어가겠습니다.



7.

    public void postNotification(String notification, Object object) {



이제 센서가 동작합니다. 동작한 센서가 변화를 감지하고 ObservingSevice에

'나 변화되었으니, 나를 관찰하고있는 녀석들에게 알려줘라'라고 요청을 하겠죠.

여기서 '나'는 notification이 될것이고, Object는 변화되는 값 혹은 Observer가 필요한 데이터가 될 것입니다.



8.

      Observable observable = observables.get(notification);


ObservingService는 자신의 HashMap에서 센서(Observable)를 찾고



9.

        if (observable!=null) {

            observable.setChanged();

            observable.notifyObservers(object);

        }


null이 아니라면 즉, 자신에게 등록되어있는 센서의 이름을 찾았다면,

해당 센서를 감지하고있는 화면(Observer)들에게 필요한 데이터(object)를 넘여주게 될겁니다.







지금까지 센서와 화면을 중앙 관리하는 ObservingService를 봤습니다.

센서(Observable)와 화면(Observer)를 보겠습니다.

대충 작성한 코드입니다 ( ㅡ,.ㅡ)

테스트 해보지 못한..ㅠ;


senser.java

public class senser {
int temperature;
ObservingService OS;

senser(){
temperature =0;
OS = new ObservingService();
}

public void setTemperature(int temperature){
this.temperature = temperature;
TemperatureChanged();
}
public void TemperatureChanged(){
OS.postNotification("thermometer", temperature) ;
}
}

1.
    public class senser {
    int temperature;
    ObservingService OS;

센서(Observable)는 감지할 온도 temperature와 화면(Obsever)들에게 변화를 알려줄 ObservingService를 갖고있습니다.


2.
    senser(){
temperature =0;
OS = new ObservingService();
}


온도의 초기값을 정해주고 ObservingService를 만들어줍니다. OS가 중앙 관리하려면 singleton으로 하는게 좋겟죠. 여기선 대충.....작성햇습니다.



3.

    public void setTemperature(int temperature){

this.temperature = temperature;
TemperatureChanged();
}


변경된 온도를 적용해 주는 소스입니다. 여기서 온도의 변화를 체크합니다.

온도가 변화 되었을때의 메서드를 실행합니다.



4.

    public void TemperatureChanged(){

OS.postNotification("thermometer", temperature) ;
}


온도의 변화를 감지한 센서(Observable)는 OS를 통해 화면(Observer)으로 알립니다.







마지막으로 화면(Observer)를 보겠습니다.


displayer.java


public class temp_displayer  implements Observer{

int temperature;

ObservingService OS;


temp_displayer (){

temperature =0;

OS = new ObservingService();

registObserver("thermometer");

}


registObserver(String notification){

OS.addObserver(notification,this);

}


cancelObserver(String notification){

OS.removeObserver(notification,this);

}


update(Object object){

temperature = (int)object;

temp_displayData();

}

temp_displayData(){

log.v("print", "temperature  : " + temperature);

}

}



1.

    public class temp_displayer  implements Observer{

int temperature;

ObservingService OS;


화면(Observer)에서는 화면에 보여줄 데이터 온도 temperature와 Observer로 등록하기 위해 필요한 OS를 갖습니다.



2.

temp_displayer (){

temperature =0;

OS = new ObservingService();

registObserver("thermometer");

}


온도 초기값0, ObservingSerivce를 가져옵니다. (마찬가지로 ObservingService를 singleton으로 만들어 둬야 기존에 Observable에 등록할 수 있겟죠)

그후에 OS를 통해 Observer로 등록합니다.



3.

registObserver(String notification){

OS.addObserver(notification,this);

}


cancelObserver(String notification){

OS.removeObserver(notification,this);

}


OS를 통해 등록하고 해제하는 메서드 입니다.



4.

update(Object object){

temperature = (int)object;

temp_displayData();

}

temp_displayData(){

log.v("print", "temperature  : " + temperature);

}


OS를 통해 불러질 update메서드 입니다. 데이터를 전달 인자로 받아다가

해당 데이터를 보여주게 됩니다.







관리할 Observable이 많지 않다면 ObservingService를 사용하지 않아도 될것 같습니다.

Observable과 Observer의 인터페이스를 만들어서  Implements를 통해 구현 해주면 되겠지요.


interface Observable{

addObserver(Observer);

removeObserver(Observer);

nofityObservers(Object);

}


interface Observer{

update(Object);

}


위와 같이 만들어 사용하면 되겠습니다.




아래의 소스는 버튼의 이름을 버튼클릭할 때마다 카운트가 올라가도록합니다.

위의 Observable과 Observer를 한번에 사용한 예입니다.

Observer를 사용하지 않고도 같은 기능을 쉽게 구현할 수 있겠지만, Observer기능을 한번 거쳐서 동작하게 했습니다.



public class CustomBtn extends Button implements Observerable,Observer{

ArrayList<Observer> observers;

String str;

public CustomBtn(Context context) {

super(context);

this.setWidth(50);

this.setHeight(20);

observers=new ArrayList<Observer>();

observers.add(this);

str="1";

this.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

int i = Integer.parseInt(str);

i++;

str = Integer.toString(i);

notifyObservers();

}

});

}

@Override

public void addObserver(Observer o) {

observers.add(o);

}

@Override

public void removeObserver(Observer o) {

observers.remove(o);

}

@Override

public void notifyObservers() {

for(int j=0; j<observers.size(); j++){

Observer observer = (Observer)observers.get(j);

observer.update(this);

}

}

@Override

public void update(Object object) {

this.setText(str);

}

}





센서와 화면에 대응해서 쉽게 설명하려 해보았습니다.


읽어주셔서 감사합니다.


반응형

댓글