1.状态模式(state)
1.1定义
当一个对象的内在状态改变时容许改变其行为。这个对象看起来像是改变了其类
1.2说明
- Context:控制类,定义客户感兴趣的接口,维护一个State子类的实例
- State:抽象状态类或者状态接口,定义一个或者以组接口,表示该状态下的行为。
- ConcreteStateA,ConcreteStateB:具体状态类,每一个具体的类实现抽象State中定义的接口。
PS:和策略模式的区别
状态模式和策略模式的结构几乎一模一样,但他们的目的, 本质却完全不一样. 状态模式的行为是平行的不可替换的. 策略模式的行为是彼此独立, 可相互替换的. 总结一句话表述: 状态模式是把对象的行为包装在不同的状态对象里, 每一个状态对象都有一个共同的抽象状态基类, 状态模式的意图是让一个对象在其内部状态改变的时候, 其行为也随之改变
1.3使用场景
- 一个代码的行为取决于它的装填, 并且必须在运行时根据其状态改变它的行为
- 代码中包含大量与对象状态有关的条件语句, 同样可以去除分支语句的效果
1.4代码实现
如果登陆成功则可以调用其他的页面,没有登陆则需要跳转到登陆界面的例子
1.状态接口
public interface UserState {
/**
* 转发
*/
public void forward(Context context);
/**
* 评论
*/
public void comment(Context context);
}
2.具体的实现类
登陆过的
public class LoginState implements UserState {
@Override
public void forward(Context context) {
Toast.makeText(context, "跳转", Toast.LENGTH_LONG).show();
}
@Override
public void comment(Context context) {
Toast.makeText(context, "评论", Toast.LENGTH_LONG).show();
}
}
未登陆的
public class LogoutState implements UserState {
@Override
public void forward(Context context) {
gotoLoginActivity(context);
}
@Override
public void comment(Context context) {
gotoLoginActivity(context);
}
private void gotoLoginActivity(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
}
}
3.控制类
public class LoginContext {
//用户状态
UserState userState = new LogoutState();
private LoginContext(){
}
//单例
private static class SingleTonHolder
{
private static LoginContext sLoginContext = new LoginContext();
}
public static LoginContext getLoginContext() {
return SingleTonHolder.sLoginContext;
}
public void setUserState(UserState userState) {
this.userState = userState;
}
public void forward(Context context) {
userState.forward(context);
}
public void comment(Context context) {
userState.forward(context);
}
}
4.调用方法
1.4优缺点
优点:状态模式将所有与一个状态相关的行为放到一个状态对象中,它提供了一个更好的方法来组织与特定状态相关的代码,将繁琐的判断换成结构清晰的状态类族,在避免代码膨胀的同时保证了可扩展和可维护性。
缺点:状态模式使用必然增加系统类和对象的个数
1.5 Android源码对相应实现
WIFI管理就是使用了状态模式
在WiFi复杂的调用中, 存在一个State的状态类, 它代表了WiFi的某个状态, 定义如下:
com\android\internal\State.java
public class State implements IState {
// 进入当前状态之后调用该函数
@Override
public void enter() {
}
// 退出该状态后改用该函数
@Override
public void exit() {
}
// 处理消息
@Override
public boolean processMessage(Message msg) {
return false;
}
}
状态之间并不是可以随意切换的, 他们有一种层级关系, 这些层级关系StateMachine的构造函数中被定义的, 代码如下:
com\android\server\WifiStaaMachine.java
public WifiStateMachine(Context context, String wlanInterface,
WifiTrafficPoller trafficPoller) {
addState(mDefaultState);
addState(mInitialState, mDefaultState);
addState(mSupplicantStartingState, mDefaultState);
addState(mSupplicantStartedState, mDefaultState);
addState(mDriverStartingState, mSupplicantStartedState);
addState(mDriverStartedState, mSupplicantStartedState);
addState(mScanModeState, mDriverStartedState);
addState(mConnectModeState, mDriverStartedState);
addState(mL2ConnectedState, mConnectModeState);
addState(mObtainingIpState, mL2ConnectedState);
addState(mVerifyingLinkState, mL2ConnectedState);
addState(mConnectedState, mL2ConnectedState);
addState(mRoamingState, mL2ConnectedState);
addState(mDisconnectingState, mConnectModeState);
addState(mDisconnectedState, mConnectModeState);
addState(mWpsRunningState, mConnectModeState);
addState(mWaitForP2pDisableState, mSupplicantStartedState);
addState(mDriverStoppingState, mSupplicantStartedState);
addState(mDriverStoppedState, mSupplicantStartedState);
addState(mSupplicantStoppingState, mDefaultState);
addState(mSoftApStartingState, mDefaultState);
addState(mSoftApStartedState, mDefaultState);
addState(mTetheringState, mSoftApStartedState);
addState(mTetheredState, mSoftApStartedState);
addState(mUntetheringState, mSoftApStartedState);
// 初始化模式为mInitialState
setInitialState(mInitialState);
}
com\android\internal\StateMachine.java
protected final void addState(State state, State parent) {
mSmHandler.addState(state, parent);
}
在构造函数中调用了addState()函数, 这些函数最终会调用mSmHandler#addState()函数. 这个函数就是在状态之间建立一个层级关系, 这是一个树形的层级关系. 状态之间并不是跨越式的转换, 当前状态只能转换到上一个状态或者下一个状态.
State的类有enter,exit,processMessage三个函数, 进入状态之后会调用enter(), 退出时调用exit(), 处理具体消息时调用processMessage(). 而状态模式的核心就是当一个对象的内在状态改变时允许改变其行为, 所以我们关注processMessage()不同的状态下就是依赖这个函数实现不同行为的.
例如: 在请求扫描Wifi时, 如果在初始化状态(InitialState)下, 说明Wifi驱动还没有进行加载和启动, 扫描的请求会被会被忽略. 而在驱动加载状态下, 请求会被添加到延迟处理的消息队列中, 等待驱动加载完毕进行扫描请求.
2.责任链模式(Chain of Responsibility)
2.1 定义
使多个对象都有机会处理请求, 从而避免了请求的发送者和接收者之间的耦合关系. 将这些对象连成一条链, 并沿着这条链传递该请求, 直到对象处理它为止
2.2使用场景
- 多个对象可以处理一个请求,但是具体由那个处理则在运行中动态决定
- 在请求处理者不明确的情况下向多个对象的一个进行提交请求。
2.3 代码实现
1.处理抽象类
public abstract class Handler {
//下一个节点处理者
protected Handler successor;
/**
* 请求处理
* @param condition 请求条件
*/
public abstract void handleRequest(String condition);
}
2.具体的实现
public class ConcreteHandler1 extends Handler {
@Override
public void handleRequest(String condition) {
if(condition.equals("ConcreteHandler1")){
System.out.println("ConcreteHandler1 handler");
}else{
successor.handleRequest(condition);
}
}
}
public class ConcreteHandler2 extends Handler {
@Override
public void handleRequest(String condition) {
if(condition.equals("ConcreteHandler2")){
System.out.println("ConcreteHandler2 handler");
}else{
successor.handleRequest(condition);
}
}
}
3.具体调用
public class Client {
public static void main(String[] args) {
ConcreteHandler1 concreteHandler1 = new ConcreteHandler1();
ConcreteHandler2 concreteHandler2 = new ConcreteHandler2();
concreteHandler1.successor = concreteHandler2;
concreteHandler2.successor = concreteHandler1;
concreteHandler2.handleRequest("ConcreteHandler1");
}
}
2.4 Android源码对应实现
View的事件分发
2.5.1 Activity分发
A.activity事件分发是先调用dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
从代码可知道:
1.是否执行onTouchEvent(ev)取决于getWindow().superDispatchTouchEvent(ev).
2.如果getWindow().superDispatchTouchEvent(ev)返回的是true则onTouchEvent不会执行。
3.getWindow()实际上是phonwindow,并在其中调用了mDecor.superDispatchTouchEvent(). DecorView继承于viewgroup,所以实际调用了父类的dispatchTouchEvent().于是进入了ViewGroup的事件分发。
B.ViewGroup事件分发
ViewGroup的dispatchTouchEvent()方法
1.先设置mFirstTouchTarget = null;
如果ViewGroup的有子元素成功处理,mFirstTouchTarget就会指向该元素
// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
cancelAndClearTouchTargets(ev);
resetTouchState();
}
/**
* Clears all touch targets.
*/
private void clearTouchTargets() {
TouchTarget target = mFirstTouchTarget;
if (target != null) {
do {
TouchTarget next = target.next;
target.recycle();
target = next;
} while (target != null);
mFirstTouchTarget = null;
}
}
2.默认情况下所有的ViewGroup都是默认不拦截的
// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
&& ev.getAction() == MotionEvent.ACTION_DOWN
&& ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
&& isOnScrollbarThumb(ev.getX(), ev.getY())) {
return true;
}
return false;
}
3.然后会查找子控件是否有事件消耗。如果找到了就会设置FirstTouchTarget不为空且设置 alreadyDispatchedToNewTouchTarget = true
for (int i = childrenCount - 1; i >= 0; i--) {
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
if (preorderedList != null) {
// childIndex points into presorted list, find original index
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
4.dispatchTransformedTouchEvent区分是本view还是child
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
final boolean handled;
// Canceling motions is a special case. We don't need to perform any transformations
// or filtering. The important part is the action, not the contents.
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
}
- 当是本view调用父类的dispatchTouchEvent也就是View的dispatchTouchEvent。
- 如果是子view这根据情况调用viewgroup或者view的dispatchTouchEvent。
C.View事件分发
dispatchTouchEvent
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
- 如果onTouchListener的onTouch方法返回了true,那么view里面的onTouchEvent就不会被调用了。
- 如果view为disenable,则:onTouchListener里面不会执行,但是会执行onTouchEvent(event)方法