관찰자 모드 와 리 셋 메커니즘 이 안 드 로 이 드 소스 코드 를 만 났 을 때
12211 단어 소스 코드 와 디자인 모델Android 소스 코드 와 디자인 모드
관찰자 모드
정의.
관찰자 모델 은 한 쌍 의 다 중 의존 관 계 를 정의 하여 여러 관찰자 대상 이 특정한 주제 대상 을 동시에 감청 하도록 한다.이 테마 대상 은 상태 가 변 할 때 모든 관찰자 대상 에 게 자동 으로 자신 을 업데이트 할 수 있 도록 알려 줍 니 다.
관찰자 모드 의 구조
관찰자 모드 와 관련 된 역할 은 다음 과 같다.
이루어지다
추상 테마 캐릭터 클래스
public abstract class Subject {
/**
*
*/
private List list = new ArrayList();
/**
*
* @param observer
*/
public void attach(Observer observer){
list.add(observer);
System.out.println("Attached an observer");
}
/**
*
* @param observer
*/
public void detach(Observer observer){
list.remove(observer);
}
/**
*
*/
public void nodifyObservers(String newState){
for(Observer observer : list){
observer.update(newState);
}
}
}
구체 적 주제 캐릭터 클래스
public class ConcreteSubject extends Subject{
private String state;
public String getState() {
return state;
}
public void change(String newState){
state = newState;
System.out.println(" :" + state);
// ,
this.nodifyObservers(state);
}
}
추상 관찰자 역할 류
public interface Observer {
/**
*
* @param state
*/
public void update(String state);
}
구체 적 관찰자 역할 류
public class ConcreteObserver implements Observer {
//
private String observerState;
@Override
public void update(String state) {
/**
* ,
*/
observerState = state;
System.out.println(" :"+observerState);
}
}
테스트 클래스
public class Test {
public static void main(String[] args) {
//
ConcreteSubject subject = new ConcreteSubject();
//
Observer observer = new ConcreteObserver();
//
subject.attach(observer);
//
subject.change("new state");
}
}
관찰자 의 두 가지 실현 방식
두 가지 방식 의 비교
리 셋 메커니즘 과 관찰자 모델
Android 에는 Activity 의 라 이 프 사이클, 버튼 클릭 이벤트, 스 레 드 의 run () 방법 등 리 셋 메커니즘 을 사용 하 는 곳 이 매우 많 습 니 다.
다음은 리 셋 의 기본 모델 입 니 다.
public interface CallBack {
public void oncall();
}
public class A {
private CallBack callback;
//
public void register(CallBack callback){
this.callback = callback;
}
//
public void call(){
callback.oncall();
}
}
public static void main(String[] args) {
A a = new A();
a.register(new CallBack() {
@Override
public void oncall() {
System.out.println(" ");
}
});
a.call();
}
이렇게 보면 리 셋 체제 와 관찰자 모델 은 일치 하 다. 차이 점 은 관찰자 모델 에서 목표 류 는 모든 관찰자 의 인용 을 유지 하고 리 셋 안 은 하나의 인용 만 유지 하 는 것 이다.
Android 의 관찰자 모드
Android 에 서 는 관찰자 모드 를 대량으로 사 용 했 고 Framework 계층 의 이벤트 구동 은 모두 관찰자 모드 를 바탕 으로 이 루어 졌 다.또한 Framework 계층 에서 의 각종 서 비 스 는 데이터 가 변 경 될 때 관찰자 모델 을 통 해 상부 데이터 업 데 이 트 를 실현 한다.뷰 의 Listener 감청, GPS 위치 정보 감청, BroadcastReceiver 등 은 모두 관찰자 모드 를 바탕 으로 이 루어 졌 다.다음은 ListView 의 관찰자 모델 이 어떻게 실현 되 었 는 지, RecyclerView 는 대동소이 하고 관심 있 는 것 은 스스로 연구 할 수 있다.
Listview 의 notifyDataSetChanged ()
먼저 listview 부분 관찰자 모드 의 구 조 를 살 펴 보 겠 습 니 다.
그 중에서 관 계 를 연구 하 는 데 편리 하도록 우 리 는 Adapter 부분의 일부 관 계 를 생략 했다.다음은 구체 적 인 호출 관 계 를 살 펴 보 자.
우선 데이터 가 바 뀌 었 을 때 adapter 의 notifyDataSetChanged () 방법 을 호출 합 니 다.
/**
* Common base class of common implementation for an {@link Adapter} that can be
* used in both {@link ListView} (by implementing the specialized
* {@link ListAdapter} interface) and {@link Spinner} (by implementing the
* specialized {@link SpinnerAdapter} interface).
*/
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public boolean hasStableIds() {
return false;
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Notifies the attached observers that the underlying data has been changed
* and any View reflecting the data set should refresh itself.
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
/**
* Notifies the attached observers that the underlying data is no longer valid
* or available. Once invoked this adapter is no longer valid and should
* not report further data set changes.
*/
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
}
상기 코드 에 따라 mDataSetObservable. notifyChanged () 방법 을 찾 을 수 있 습 니 다.
/**
* A specialization of {@link Observable} for {@link DataSetObserver}
* that provides methods for sending notifications to a list of
* {@link DataSetObserver} objects.
*/
public class DataSetObservable extends Observable {
/**
* Invokes {@link DataSetObserver#onChanged} on each observer.
* Called when the contents of the data set have changed. The recipient
* will obtain the new contents the next time it queries the data set.
*/
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
/**
* Invokes {@link DataSetObserver#onInvalidated} on each observer.
* Called when the data set is no longer valid and cannot be queried again,
* such as when the data set has been closed.
*/
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
notifyChanged () 방법 을 호출 하면 mObserver 를 옮 겨 다 니 며 모든 관찰자 의 onchange () 방법 을 호출 합 니 다.
그렇다면 문제 가 생 겼 다. 우리 관찰자 대상 은 언제 추 가 됐 을 까?ListView 가 처음으로 BaseAdapter 와 연 결 된 곳, 즉 setAdapter (ListAdapter adapter) 방법 을 살 펴 보 자.
@Override
public void setAdapter(ListAdapter adapter) {
// Adapter, 。
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
//
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
//
mDataSetObserver = new AdapterDataSetObserver();
// DataSetObservable
mAdapter.registerDataSetObserver(mDataSetObserver);
//
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
requestLayout();
}
이렇게 해서 우리 의 네 가지 역할 이 다 되 었 다. Observable - > Subject;DataSetObservable—>Concrete Subject;DataSetObserver—>Observer;AdapterDataSetObserver—>Concrete Observer。그리고 우리 가 등록 한 곳 도 찾았어 요.
마지막 으로 우리 의 데이터 가 어떻게 이 문 제 를 갱신 하 는 지 남 았 다.AdapterDataSetObserver 는 ListView 의 부모 클래스 AbsListView 에 정의 되 어 있 으 며, AbsListView 의 부모 클래스 AdapterView 의 AdapterDataSetObserver 를 계승 합 니 다.
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
// Adapter notifyDataSetChanged onChanged ,
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
// Adapter
mItemCount = getAdapter().getCount();
// Detect the case where a cursor that was previously invalidated has
// been repopulated with new data.
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
// ListView、GridView AdapterView
requestLayout();
}
//
public void clearSavedState() {
mInstanceState = null;
}
}
requestLayout () 방법 은 View 에서 실현 되 고 하위 View 는 필요 에 따라 다시 씁 니 다.주석 좀 봅 시다.
/*Call this when something has changed which has invalidated the layout of this view. This will schedule a layout pass of the view tree./
자, 여기까지 의 모든 호출 관 계 를 우 리 는 기본적으로 알 게 되 었 다.ListView 의 데이터 가 변 할 때 Adapter 의 notifyDataSetChanged 함 수 를 호출 합 니 다. 이 함 수 는 DataSetObservable 의 notifyChanged 함 수 를 호출 합 니 다. 이 함 수 는 모든 관찰자 (AdapterDataSetObserver) 의 onChanged 방법 을 호출 합 니 다.onChanged 함수 에서 Adapter 의 데이터 세트 의 새로운 수량 을 가 져 온 다음 ListView 의 requestLayout () 방법 으로 레이아웃 을 다시 하고 사용자 인터페이스 를 업데이트 합 니 다.
되는대로 정리 하 다
ListView 는 주로 Adapter 와 관찰자 모델 을 활용 하여 확장 성, 유연성 이 매우 강하 지만 결합 도 는 낮 습 니 다. 이것 은 디자인 모델 이 Android 소스 코드 에서 우수한 활용 사례 라 고 생각 합 니 다.그러면 우 리 는 ListView 구성 요 소 를 실현 하기 위해 더 아름 다운 방법 이 있 는 지 생각 하기 시작 해 야 한다. 우 리 는 이 실현 방향 을 어디 에 응용 할 수 있 습 니까?
사람 은 생각 할 줄 아 는 갈대 다. 생각 하면 서 우 리 는 남 의 눈 에 큰 신 이 된다.
참조 링크:
http://www.itdadao.com/articles/c15a265623p0.html
http://blog.csdn.net/bboyfeiyu/article/details/44040533
http://www.cnblogs.com/mythou/p/3370340.html