嘿,朋友们!今天咱们来聊一个让很多Android新手又爱又恨的东西——Handler消息机制里的Message类。如果你曾经因为App卡成PPT而被产品经理追杀,或者因为线程不同步导致数据乱飞,那么这篇文章就是你的救命稻草!
第一章 为什么需要Message?一个外卖小哥的比喻
想象一下,你正在厨房(主线程)里热火朝天地炒菜,突然顾客说要加一瓶可乐。你有两个选择:
- 自己跑去超市(网络请求)买可乐,让整个厨房停摆
- 叫个外卖小哥(Message)帮你买
只要脑子没进水,你肯定会选第二个方案对吧?在Android世界里,Message就是那个任劳任怨的外卖小哥!
为什么不能直接跨线程操作?
// 错误示范!这是在作死
public void updateUIFromWorkerThread() {
new Thread(() -> {
// 在子线程中直接更新UI
textView.setText("Hello from background!"); // 崩溃警告!
}).start();
}
看到没?Android系统是个强迫症患者,它规定:只有主线程才能更新UI!为什么?因为如果多个线程同时操作UI,你的屏幕可能会变成抽象画。
第二章 Message的身份证:揭秘核心字段
每个Message小哥出门送快递时,都得带上一张“送货单”,这就是Message的各个字段:
1. what - 这是送什么货?
// 定义消息类型
static final int MSG_ORDER_FOOD = 1;
static final int MSG_PAY_BILL = 2;
static final int MSG_COMPLAIN = 3;
Message msg = Message.obtain();
msg.what = MSG_ORDER_FOOD; // 明确这是下单消息
what就像快递单上的“货物类型”,让接收方一眼就知道这是什么业务。
2. arg1、arg2 - 轻量级数据
// 传递数量、价格等整型数据
msg.arg1 = 2; // 2份炸鸡
msg.arg2 = 99; // 单价99元
这两个是消息的“小口袋”,适合装一些简单的整数,比用对象高效多了!
3. obj - 大件货物
// 传递复杂对象
FoodOrder order = new FoodOrder("炸鸡", 2, "多加辣");
msg.obj = order; // 把整个订单对象塞进去
obj是Message的“后备箱”,什么大件货物都能装,但要注意序列化问题。
4. when - 准时达还是定时送
// 定时消息
handler.sendMessageDelayed(msg, 5000); // 5秒后再发送
这个字段控制消息什么时候被处理,实现延迟操作。
第三章 高级玩法:让Message变身特快专递
Bundle - 超级储物箱
// 如果要传递多个数据,用Bundle更合适
Message msg = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("food_name", "麻辣小龙虾");
bundle.putInt("quantity", 3);
bundle.putDouble("price", 188.0);
msg.setData(bundle);
Bundle就像给Message配了个多功能行李箱,各种类型的数据都能装。
callback - 带回执的快递
// 消息处理完后执行回调
Message msg = Message.obtain(handler, () -> {
Log.d("Callback", "消息已妥投,请给五星好评!");
});
第四章 性能优化:别让Message把你内存撑爆
很多新手会犯这个错误:
// 错误示范:疯狂new Message
for (int i = 0; i < 1000; i++) {
Message msg = new Message(); // 内存杀手!
handler.sendMessage(msg);
}
正确的打开方式:
// 正确做法:使用对象池
for (int i = 0; i < 1000; i++) {
Message msg = Message.obtain(); // 从池中获取,复用对象
handler.sendMessage(msg);
}
为什么推荐Message.obtain()?因为它使用了对象池模式,相当于Message回收站,避免了频繁创建销毁对象的开销。
第五章 实战:打造一个不卡顿的聊天应用
下面我们来个完整的例子,实现一个简易聊天室:
1. 先定义消息类型
public class ChatActivity extends AppCompatActivity {
private static final int MSG_RECEIVE_TEXT = 1;
private static final int MSG_RECEIVE_IMAGE = 2;
private static final int MSG_SEND_SUCCESS = 3;
private static final int MSG_SEND_FAILED = 4;
private TextView chatDisplay;
private Handler uiHandler;
// 模拟网络请求的线程
private Thread networkThread;
}
2. 创建Handler - 消息调度中心
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
chatDisplay = findViewById(R.id.chat_display);
uiHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case MSG_RECEIVE_TEXT:
String text = (String) msg.obj;
appendMessage("好友: " + text);
break;
case MSG_RECEIVE_IMAGE:
Bitmap image = (Bitmap) msg.obj;
displayImage(image);
break;
case MSG_SEND_SUCCESS:
showToast("发送成功");
break;
case MSG_SEND_FAILED:
showToast("发送失败: " + msg.arg1);
break;
}
}
};
startNetworkListening();
}
3. 模拟网络线程接收消息
private void startNetworkListening() {
networkThread = new Thread(() -> {
try {
// 模拟接收网络消息
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(2000); // 每2秒收一条消息
Message msg = Message.obtain();
msg.what = MSG_RECEIVE_TEXT;
msg.obj = "你好啊!现在是" + new Date();
uiHandler.sendMessage(msg);
}
} catch (InterruptedException e) {
Log.d("Chat", "网络线程结束");
}
});
networkThread.start();
}
4. 发送消息的方法
public void sendMessage(String text) {
// 立即在UI上显示自己发的消息
appendMessage("我: " + text);
// 模拟网络发送
new Thread(() -> {
try {
Thread.sleep(1000); // 模拟网络延迟
Message resultMsg = Message.obtain();
// 90%概率成功,10%概率失败
if (Math.random() > 0.1) {
resultMsg.what = MSG_SEND_SUCCESS;
} else {
resultMsg.what = MSG_SEND_FAILED;
resultMsg.arg1 = (int) (Math.random() * 1000); // 错误码
}
uiHandler.sendMessage(resultMsg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
5. 界面交互
public void onSendButtonClick(View view) {
EditText input = findViewById(R.id.message_input);
String text = input.getText().toString();
if (!text.isEmpty()) {
sendMessage(text);
input.setText("");
}
}
private void appendMessage(String text) {
String current = chatDisplay.getText().toString();
chatDisplay.setText(current + "\n" + text);
}
private void displayImage(Bitmap image) {
// 显示图片的逻辑
}
private void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
第六章 那些年我们踩过的坑
坑1:内存泄漏(经典必考!)
// 错误示范:匿名内部类持有外部引用
public class LeakyActivity extends AppCompatActivity {
private Handler leakyHandler = new Handler() { // 警告:可能引起内存泄漏!
@Override
public void handleMessage(Message msg) {
// 隐式持有LeakyActivity的引用
}
};
}
解决方案:
// 使用静态内部类 + 弱引用
public class SafeActivity extends AppCompatActivity {
private static class SafeHandler extends Handler {
private final WeakReference<SafeActivity> activityRef;
SafeHandler(SafeActivity activity) {
activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
SafeActivity activity = activityRef.get();
if (activity != null) {
// 处理消息
}
}
}
}
坑2:消息堆积导致卡顿
// 如果消息处理太慢,会导致消息队列堆积
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
try {
Thread.sleep(1000); // 每条消息处理1秒 → 灾难!
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
解决方案:
// 繁重任务在子线程处理,只把结果用Message发回UI线程
handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 只做轻量的UI更新
updateUI(msg.obj);
}
};
// 繁重任务在后台处理
new Thread(() -> {
Object result = doHeavyWork();
Message msg = Message.obtain(handler, 0, result);
handler.sendMessage(msg);
}).start();
第七章 Message的高级用法
1. 定时任务
// 实现轮询
private void startPolling() {
final int POLL_INTERVAL = 5000; // 5秒
Handler handler = new Handler();
Runnable pollTask = new Runnable() {
@Override
public void run() {
checkForUpdates();
handler.postDelayed(this, POLL_INTERVAL);
}
};
handler.postDelayed(pollTask, POLL_INTERVAL);
}
2. 消息优先级
// 紧急消息优先处理
Message normalMsg = Message.obtain();
normalMsg.what = NORMAL_MSG;
Message urgentMsg = Message.obtain();
urgentMsg.what = URGENT_MSG;
handler.sendMessage(normalMsg);
handler.sendMessageAtFrontOfQueue(urgentMsg); // 插队!
总结
看到这里,恭喜你已经从Message新手村毕业了!记住这几个核心要点:
- Message是线程间的信使,让UI线程和工作线程各司其职
- 善用what字段明确消息意图,代码更清晰
- 多用obtain(),少用new Message(),性能更好
- 警惕内存泄漏,使用静态Handler+弱引用
- 繁重任务别放handleMessage里,否则会阻塞UI
Message机制就像Android开发的交通规则,掌握好了,你的App就能在信息的车水马龙中畅通无阻。现在就去重构你的代码吧,让产品经理对你刮目相看!
956

被折叠的 条评论
为什么被折叠?



