观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。--摘自图说设计模式
首先,提出本文的几个问题
1.什么是观察者模式?
2.RecyclerView 中 Adapter.notifyDataSetChanged为什么能刷新页面?
3.RecyclerView中的观察者,在哪里注册和注销的?
什么是观察者模式?
可能对于部分初学者来说,还不是很清楚观察者设计模式是什么,那么接下来我会举个小例子来描述下观察者模式
被观察者
一个被观察者会对应多个观察者,观察者都会集合到这里,等待有变化时遍历通知观察者
public interface IObservable<U, T> {
void registerObserver(T observer);
void unRegisterObserver(T observer);
void userUpdate(U user);
}
public class Observable<U, T extends Observer<U>> implements IObservable<U, T> {
private List<T> observers;
public Observable() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(T observer) {
observers.add(observer);//所有的观察者都添加到观察者集合
}
@Override
public void unRegisterObserver(T observer) {
observers.remove(observer);//取消订阅从集合中移除
}
@Override
public void userUpdate(U u) {
for (T observer : observers) {
observer.update(u);//遍历通知观察者
}
}
}
观察管理类,被观察者的具体实现
public class ObserverManager {
private static volatile ObserverManager mInstance;
private IObservable<User, Observer<User>> observable;
private ObserverManager() {
observable = new Observable<>();
}
public static ObserverManager getInstance() {
if (mInstance == null) {
synchronized (ObserverManager.class) {
if (mInstance == null) {
mInstance = new ObserverManager();
}
}
}
return mInstance;
}
public void addUpdate(User user) {
observable.userUpdate(user);
}
public void registerObserver(Observer<User> observer) {
observable.registerObserver(observer);
}
public void unRegisterObserver(Observer<User> observer) {
observable.unRegisterObserver(observer);
}
}
观察者
将MainActivity注册为观察者,实现update()方法
public class MainActivity extends AppCompatActivity implements Observer<User> {
private TextView showTv;
private List<User> users;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showTv = findViewById(R.id.showTv);
ObserverManager.getInstance().registerObserver(this);
users = new ArrayList<>();
}
public void click(View view) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
@Override
public void update(User user) {
users.add(user);
showTv.setText(users.toString());
}
@Override
protected void onDestroy() {
super.onDestroy();
ObserverManager.getInstance().unRegisterObserver(this);
}
}
在SecondActivity 中通知观察者
public class SecondActivity extends AppCompatActivity {
private EditText nameEd;
private EditText ageEd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
nameEd = findViewById(R.id.nameEd);
ageEd = findViewById(R.id.ageEd);
}
public void addUser(View view) {
User user = new User(nameEd.getText().toString(), ageEd.getText().toString());
ObserverManager.getInstance().addUpdate(user);
}
public void finishPager(View view) {
finish();
}
}
在SecondActivity输入名字和年龄,点击添加通知观察者,点击添加完毕关闭SecondActivity回到MainActivity


总结一下
1.观察者注册时添加到被观察者中的集合,以便被观察者遍历通知观察者
2.JDK中自带了观察者模式(被观察者Observable、观察者Observer),自带的Observer的update方法中传递的参数类型是Object,需要强转
3.Android源码中观察者模式运用较多,在RecyclerView和ListView中都有使用
回归正题
RecyclerView 中 Adapter.notifyDataSetChanged
直接来到RecyclerView内部类Adapter中
public abstract static class Adapter<VH extends ViewHolder> {
private final AdapterDataObservable mObservable = new AdapterDataObservable();
//此处省略了很多代码
}
可以看到在Adapter中实例化了AdapterDataObservable,AdapterDataObservable继承自Observable,在Observable中实现了Adapter状态改变通知观察者的方法
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
public boolean hasObservers() {
return !mObservers.isEmpty();
}
public void notifyChanged() {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
public void notifyItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(positionStart, itemCount, null);
}
public void notifyItemRangeChanged(int positionStart, int itemCount,
@Nullable Object payload) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
}
}
public void notifyItemRangeInserted(int positionStart, int itemCount) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
}
}
public void notifyItemRangeRemoved(int positionStart, int itemCount) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
}
}
public void notifyItemMoved(int fromPosition, int toPosition) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeMoved(fromPosition, toPosition, 1);
}
}
}
再来到RecyclerView中,可以看到在RecyclerView初始化了观察者RecyclerViewDataObserver
public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {
//此处省略了大量代码
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
//此处省略了大量代码
}
在Adapter的观察者状态改变时就会通知到观察者RecyclerViewDataObserver中的方法,在收到通知时调用了requestLayout() 方法,requestLayout()会调用到View的requestLayout()方法,然后在view中会去到ViewRootImpl中去自上而下刷新布局,RecyclerView中的布局就会被刷新
private class RecyclerViewDataObserver extends AdapterDataObserver {
RecyclerViewDataObserver() {
}
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
processDataSetCompletelyChanged(true);
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) {
triggerUpdateProcessor();
}
}
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
}
@Override
public void requestLayout() {
if (mInterceptRequestLayoutDepth == 0 && !mLayoutFrozen) {
super.requestLayout();
} else {
mLayoutWasDefered = true;
}
}
第三个问题
RecyclerView中的观察者,在哪里注册和注销的?
private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
if (mAdapter != null) {//防止有开发者多次调用setAdapter,多次注册观察者
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
if (!compatibleWithPrevious || removeAndRecycleViews) {
removeAndRecycleViews();
}
mAdapterHelper.reset();
final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
if (adapter != null) {
adapter.registerAdapterDataObserver(mObserver);//在这里注册
adapter.onAttachedToRecyclerView(this);
}
if (mLayout != null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
}
注销
public void unregisterAdapterDataObserver(@NonNull AdapterDataObserver observer) {
mObservable.unregisterObserver(observer);
}
总结
文章开头的三个问题已经解答完毕。
网友评论