一句话总结:
命令模式就像「外卖订单」—— 把用户请求(点菜)封装成对象(订单),交给系统(骑手)处理,Android 里的点击事件、异步任务、Activity启动都用这套机制解耦执行流程!
一、命令模式的核心思想
核心要素:
- 命令(Command) :封装操作请求(如
Runnable、Intent) - 调用者(Invoker) :触发命令执行(如
Handler、View) - 接收者(Receiver) :实际执行操作的对象(如
ActivityThread、Button)
类比场景:
- 顾客(Client) → 点宫保鸡丁(Command)
- 服务员(Invoker) → 传递订单给后厨
- 厨师(Receiver) → 实际炒菜
二、Android 源码中的命令模式案例
1. Handler 的 Runnable 命令
// 定义命令
Runnable task = new Runnable() {
@Override
public void run() {
updateUI(); // 实际执行的操作
}
};
// 调用者发送命令
Handler handler = new Handler(Looper.getMainLooper());
handler.post(task); // 将命令加入消息队列
// 底层实现:Message 携带命令
public class Handler {
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; // 命令存储在 Message 中
return m;
}
// 分发执行命令
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
msg.callback.run(); // 执行 Runnable 命令
}
}
}
设计亮点:
- 将异步操作封装成
Runnable命令对象 Handler作为调用者统一管理命令队列
2. Activity 启动的 Intent 命令
// 封装启动命令
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("key", "value");
// 触发命令执行
startActivity(intent);
// 源码流程:
// - Activity.startActivity() → Instrumentation.execStartActivity()
// - 通过 Binder 发送 Intent 命令到 ActivityManagerService (AMS)
// - AMS 处理命令,启动目标 Activity
关键源码:
// frameworks/base/core/java/android/app/Activity.java
public void startActivity(Intent intent) {
startActivityForResult(intent, -1);
}
// frameworks/base/core/java/android/app/Instrumentation.java
public ActivityResult execStartActivity(...) {
// 跨进程调用 AMS
int result = ActivityTaskManager.getService().startActivity(...);
}
命令传递:
Intent 作为命令对象,跨进程传输 → AMS 解析并执行
3. 点击事件的 OnClickListener
// 定义命令
View.OnClickListener clickCommand = new View.OnClickListener() {
@Override
public void onClick(View v) {
handleClick();
}
};
// 设置命令到调用者
button.setOnClickListener(clickCommand);
// 源码实现:View 处理命令分发
public class View implements OnClickListener {
private OnClickListener mOnClickListener;
public void setOnClickListener(OnClickListener l) {
mOnClickListener = l; // 存储命令
}
// 触发执行
public void performClick() {
if (mOnClickListener != null) {
mOnClickListener.onClick(this);
}
}
}
三、命令模式的底层优势
1. 解耦请求与实现
- 发送者(如 Button)不关心谁处理点击
- 接收者(如 Activity)可灵活替换处理逻辑
2. 支持命令队列与撤销
// 实现命令队列
Queue<Runnable> commandQueue = new LinkedList<>();
commandQueue.offer(task1);
commandQueue.offer(task2);
// 依次执行
while (!commandQueue.isEmpty()) {
commandQueue.poll().run();
}
// 实现撤销(需命令对象记录状态)
public interface UndoableCommand {
void execute();
void undo();
}
3. 跨进程通信的天然适配
Intent通过 Binder 传递,天然符合命令模式- 序列化机制(Parcelable)保证命令对象可传输
四、命令模式在开源框架中的应用
1. Retrofit 的 Call 命令
// 定义网络请求命令
Call<User> call = retrofit.create(UserService.class).getUser(123);
// 异步执行命令
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
// 处理响应(相当于命令执行结果)
}
});
2. RxJava 的 Action 命令
Observable.just("Hello")
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) { // 命令执行
System.out.println(s);
}
});
五、总结与最佳实践
使用场景口诀
「点击异步加跳转,命令模式解耦强
需要队列或撤销,此模式是好搭档」
Android 源码对照表
| 场景 | 命令对象 | 调用者 | 接收者 |
|---|---|---|---|
| 异步任务 | Runnable | Handler | Looper/主线程 |
| Activity 跳转 | Intent | Activity | ActivityManagerService |
| 点击事件 | OnClickListener | View | 实现接口的 Activity |
注意事项
- 简单回调无需过度设计成命令模式
- 注意匿名内部类导致的内存泄漏(如
Runnable持有 Activity 引用) - 跨进程命令要确保
Parcelable正确实现
总结口诀:
「请求封装成命令,解耦调用和执行
Handler 发 Runnable,Intent 跳转 Activity
队列撤销都能做,灵活扩展显威力」