new Handler().obtainMessage().sendToTarget()过程分析

new Handler().obtainMessage().sendToTarget()这句话用着真爽,一行代码就能搞定异步消息了!所以在代码中使用的算是非常频繁的了,那这又是一个什么样的过程呢? 这个过程中又有什么玄机呢? 这篇文章,我们来一步步的分析一下这三句话。


1、new Handler()的分析

new Handler()会辗转来到public Handler(Callback callback, boolean async)这个构造方法。在这个构造方法中会获取当前Looper

mLooper = Looper.myLooper();

而此时的Looper是默认的那个Looper,即在ActivityThreadmain方法中prepare的Looper

在ActivityThread.main中:

Looper.prepareMainLooper();
...
Looper.loop();

此时Handler和Looper有了关联。


2、obtainMessage()的分析

在Handler.obtainMessage()中会调用Message.obtain(this)。
Message.obtain()的源码:

public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;
        return m;
  }

obtain从消息池中构造一个message,并将messagetarget置为传进来的handler


此时handlermessage有了关联。


3、sendToTarget()的分析

public void sendToTarget() {
        target.sendMessage(this);
}
直接调用target.sendMessage,而target正是当前的Handler。
继续跟踪target.sendMessage(this) target中发送消息会辗转来到private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
在这个方法中有去调用queue.enqueueMessage.

继续跟踪queue.enqueueMessage,这个方法有点长,主要是将当前Message压入消息队列中:

...
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
    // New head, wake up the event queue if blocked.
    msg.next = p;
    mMessages = msg;
    needWake = mBlocked;
} else {
    // Inserted within the middle of the queue.  Usually we don't have to wake
    // up the event queue unless there is a barrier at the head of the queue
    // and the message is the earliest asynchronous message in the queue.
    needWake = mBlocked && p.target == null && msg.isAsynchronous();
    Message prev;
    for (;;) {
         prev = p;
         p = p.next;
         if (p == null || when < p.when) {
                break;
          }
         if (needWake && p.isAsynchronous()) {
               needWake = false;
          }
     }
     msg.next = p; // invariant: p == prev.next
     prev.next = msg;
 }

// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
     nativeWake(mPtr);
}
...




这里面的MessageQueue就是在Handler保存的那个MessageQueue,也就是说此时,这个Message已经保存到Handler中的那个消息队列中了。而,我们Handler中的MessageQueue哪来的呢? 来看看这行代码:

public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
...
mQueue = mLooper.mQueue;
...
}

Handler中的MessageQueue正式从Looper中获取的,这个Looper当然就是在ActivityThread中prepare的那个。


顺一下此时的关系:Handler中保存了ActivityThread中的Looper,并从该Looper中获取了MessageQueue;调用obtainMessage,实质上是创建了一个Message对象,并将Message对象的target设置为现在的Handler;调用Message.sendToTarget()实际是调用了Message.target.sendMessage(),即Handler.sendMessage,而Handler.sendMessage会来到enqueueMessage方法,在这个方法中调用MessageQueue.enqueueMessage将消息压缩刚开始我们获取的那个MessageQueue。


此时,再来看看Looper.loop()是怎么将消息回调到handleMessage中的:

for (;;) {
        Message msg = queue.next(); // might block
        ...
        msg.target.dispatchMessage(msg);
        ...
        msg.recycle();
 }

继续看看Handler.dispatchMessage():

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
}

转来转去,终于把Message回调到了handleMessage!!!
从源码中,我们也能看出, sendToTarget()方法并不是真正的将Message发送出去,而是将Message压入了MessageQueue中,真正去回调handleMessage还是在Looper.loop()中完成的。



package com.example.demoapplication; import android.Manifest; import android.content.pm.PackageManager; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.AudioTrack; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.speech.tts.TextToSpeech; import android.util.Base64; import android.util.Log; import android.widget.Button; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener { // 日志标签和UI组件定义 private static final String TAG = "AudioRecorder"; private Button startRecordButton, stopRecordButton; private AudioRecord audioRecord; // 音频采样率和缓冲区大小配置 private static final int SAMPLE_RATE = 16000; private static final int BUFFER_SIZE; static { // 计算最小缓冲区大小并确保不小于4096字节 int minBufferSize = AudioRecord.getMinBufferSize( SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT ); BUFFER_SIZE = Math.max(minBufferSize, 4096); } // 线程池和服务状态变量 private ScheduledExecutorService scheduler; private AtomicBoolean isRecording = new AtomicBoolean(false); private static final int PERMISSION_REQUEST_CODE = 1; private final ExecutorService executorService = Executors.newCachedThreadPool(); // 网络通信相关变量 private ServerSocket serverSocket; private volatile boolean isServerRunning = true; private volatile Socket clientSocket; private volatile BufferedWriter socketWriter; // 文字转语音(TTS)引擎和播放器 private TextToSpeech ttsEngine; private boolean isTtsInitialized = false; private AudioTrack audioTrack; // 控制是否已发送开始/结束提示 private boolean isStartMessageSent = false; private boolean isStopMessageSent = false; private boolean isTransmitStarted = false; // 新增标志位控制startTransmit只显示一次 private boolean isStopTransmitSent = false; // 新增标志位控制stopTransmit只显示一次 // 主线程消息处理器 private final Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { case 0x11: // 客户端连接 Toast.makeText(MainActivity.this, "客户端已连接", Toast.LENGTH_SHORT).show(); break; case 0x12: // 开始录音 // 每次都显示Toast,但保留标志位用于其他用途 Toast.makeText(MainActivity.this, "开始录音", Toast.LENGTH_SHORT).show(); isStartMessageSent = true; isStopMessageSent = false; sendControlPacket("startRecorder"); // 发送开始录音指令给客户端 playTts("开始录音"); // 触发TTS播报"开始录音" break; case 0x13: // 数据发送 break; case 0x14: // 停止录音 // 强制显示Toast,忽略标志位检查 Toast.makeText(MainActivity.this, "停止录音", Toast.LENGTH_SHORT).show(); isStopMessageSent = true; isStartMessageSent = false; sendControlPacket("stopRecorder"); // 发送停止录音指令给客户端 playTts("停止录音"); // 触发TTS播报"停止录音" break; case 0x15: // 控制指令 Toast.makeText(MainActivity.this, "收到指令: " + msg.obj, Toast.LENGTH_SHORT).show(); break; case 0x16: // 错误 Toast.makeText(MainActivity.this, "错误: " + msg.obj, Toast.LENGTH_LONG).show(); break; case 0x18: // TTS音频 handleTtsAudio((String) msg.obj); break; case 0x19: // 聊天开始 Toast.makeText(MainActivity.this, "聊天开始: " + msg.obj, Toast.LENGTH_SHORT).show(); break; case 0x20: // 聊天回复 Toast.makeText(MainActivity.this, "回复: " + msg.obj, Toast.LENGTH_LONG).show(); break; case 0x21: // 播放完成 Toast.makeText(MainActivity.this, "播放完成", Toast.LENGTH_SHORT).show(); break; } } }; // Activity生命周期方法 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化TTS引擎 ttsEngine = new TextToSpeech(this, this); initViews(); setupClickListeners(); checkPermissions(); startServer(30000); } // 初始化视图控件 private void initViews() { startRecordButton = findViewById(R.id.startRecordButton); stopRecordButton = findViewById(R.id.stopRecordButton); stopRecordButton.setEnabled(false); } // 设置按钮点击事件监听器 private void setupClickListeners() { startRecordButton.setOnClickListener(v -> startRecording()); stopRecordButton.setOnClickListener(v -> stopRecording()); } // 检查录音权限 private void checkPermissions() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSION_REQUEST_CODE); } } // 开始录音操作 private void startRecording() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { sendErrorMessage("没有录音权限"); return; } if (isRecording.get()) { // 允许重复启动:如果已经在录音,先释放资源 releaseAudioResources(); } if (clientSocket == null || clientSocket.isClosed() || socketWriter == null) { sendErrorMessage("客户端未连接"); return; } try { // 创建并初始化AudioRecord对象 audioRecord = new AudioRecord( MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE ); if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { throw new IllegalStateException("AudioRecord 初始化失败"); } // 启动录音,更新UI状态,启动定时上传任务 audioRecord.startRecording(); isRecording.set(true); startRecordButton.setEnabled(false); stopRecordButton.setEnabled(true); // 如果已有调度器,先关闭再新建 if (scheduler != null) { scheduler.shutdownNow(); } scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(this::uploadAudioData, 0, 100, TimeUnit.MILLISECONDS); handler.sendEmptyMessage(0x12); sendControlPacket("startRecorder"); playTts("开始录音"); } catch (Exception e) { Log.e(TAG, "录音启动失败", e); sendErrorMessage("录音启动失败: " + e.getMessage()); releaseAudioResources(); } } // 停止录音操作 private void stopRecording() { if (!isRecording.get()) return; isRecording.set(false); releaseAudioResources(); stopRecordButton.setEnabled(false); startRecordButton.setEnabled(true); // 允许再次开始录音 // 总是重置标志位以允许下次显示开始/停止提示 isStopMessageSent = false; isStartMessageSent = false; handler.sendEmptyMessage(0x14); sendControlPacket("stopRecorder"); playTts("停止录音"); } // 播放TTS语音 private void playTts(String text) { if (isTtsInitialized) { ttsEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null); Log.i(TAG, "播放TTS: " + text); } } // 释放录音资源 private void releaseAudioResources() { if (audioRecord != null) { try { if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { audioRecord.stop(); } } catch (IllegalStateException e) { Log.e(TAG, "停止录音失败", e); } audioRecord.release(); audioRecord = null; } if (scheduler != null) { scheduler.shutdownNow(); scheduler = null; } } // 上传音频数据到服务器 private void uploadAudioData() { if (!isRecording.get() || clientSocket == null || clientSocket.isClosed() || socketWriter == null) { return; } byte[] buffer = new byte[BUFFER_SIZE]; try { int bytesRead = audioRecord.read(buffer, 0, BUFFER_SIZE); if (bytesRead > 0) { // 首次读取数据时发送开始指令,并且仅发送一次 if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING && !isTransmitStarted) { sendControlPacket("startTransmit"); // 发送开始传输指令 playTts("开始传输"); // 触发TTS播报"开始传输" audioRecord.startRecording(); // 确保录音已开始 isTransmitStarted = true; // 标记为已发送 } // 在最后一次读取数据后发送停止传输指令 if (bytesRead < BUFFER_SIZE / 2 && isTransmitStarted) { sendControlPacket("stopTransmit"); // 发送停止传输指令 playTts("停止传输"); // 触发TTS播报"停止传输" isTransmitStarted = false; // 重置标志位以便下次使用 } JSONObject json = new JSONObject(); json.put("type", "recording"); json.put("data", Base64.encodeToString(buffer, 0, bytesRead, Base64.NO_WRAP)); synchronized (this) { if (socketWriter != null) { socketWriter.write(json.toString()); socketWriter.write("\n\n"); socketWriter.flush(); } } } } catch (Exception e) { Log.e(TAG, "发送音频数据失败", e); sendErrorMessage("发送音频数据失败: " + e.getMessage()); } } // TTS初始化回调 @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { int result = ttsEngine.setLanguage(Locale.CHINESE); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Log.e(TAG, "TTS语言不支持中文"); } else { isTtsInitialized = true; } } } // 发送控制指令包 private void sendControlPacket(String type) { if (clientSocket == null || clientSocket.isClosed() || socketWriter == null) { return; } try { JSONObject packet = new JSONObject(); packet.put("type", type); synchronized (this) { if (socketWriter != null) { socketWriter.write(packet.toString()); socketWriter.write("\n\n"); socketWriter.flush(); } } } catch (Exception e) { Log.e(TAG, "发送控制指令失败", e); } } // 发送错误信息到主线程 private void sendErrorMessage(String message) { handler.obtainMessage(0x16, message).sendToTarget(); } // 启动TCP服务器 private void startServer(int port) { executorService.execute(() -> { try { serverSocket = new ServerSocket(port); Log.i(TAG, "服务器启动: " + port); while (isServerRunning) { try { Socket socket = serverSocket.accept(); clientSocket = socket; synchronized (this) { socketWriter = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), "UTF-8")); } handler.sendEmptyMessage(0x11); executorService.execute(() -> startCommunication(socket)); } catch (IOException e) { if (isServerRunning) Log.e(TAG, "接受连接失败", e); } } } catch (IOException e) { Log.e(TAG, "服务器启动失败", e); runOnUiThread(() -> Toast.makeText(this, "服务器启动失败: " + e.getMessage(), Toast.LENGTH_LONG).show()); } finally { closeServerSocket(); } }); } // 处理客户端通信 private void startCommunication(Socket socket) { try (BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream(), "UTF-8"))) { StringBuilder packetBuilder = new StringBuilder(); int c; while ((c = reader.read()) != -1 && isServerRunning) { char ch = (char) c; packetBuilder.append(ch); if (packetBuilder.length() >= 2 && packetBuilder.charAt(packetBuilder.length() - 2) == '\n' && packetBuilder.charAt(packetBuilder.length() - 1) == '\n') { String packet = packetBuilder.toString().trim(); packetBuilder.setLength(0); if (!packet.isEmpty()) { try { JSONObject jsonObject = new JSONObject(packet); handleReceivedPacket(jsonObject); } catch (JSONException e) { Log.w(TAG, "JSON解析失败: " + packet, e); } } } } } catch (IOException e) { if (isServerRunning) { Log.e(TAG, "通信中断", e); } } finally { closeSocket(socket); } } // 处理接收到的数据包 private void handleReceivedPacket(JSONObject jsonObject) { try { String type = jsonObject.getString("type"); Object data = jsonObject.opt("data"); Message msg; switch (type) { case "tts_audio": msg = handler.obtainMessage(0x18, data.toString()); handler.sendMessage(msg); break; case "chat_start": msg = handler.obtainMessage(0x19, jsonObject.getJSONObject("data").getString("query")); handler.sendMessage(msg); break; case "chat_reply": msg = handler.obtainMessage(0x20, jsonObject.getJSONObject("data").getString("reply")); handler.sendMessage(msg); break; case "play_complete": handler.sendEmptyMessage(0x21); break; default: msg = handler.obtainMessage(0x15, type + ": " + data); handler.sendMessage(msg); break; } } catch (JSONException e) { Log.e(TAG, "处理数据包失败", e); } } // 处理TTS音频数据 private void handleTtsAudio(String base64Data) { byte[] pcmData = Base64.decode(base64Data, Base64.DEFAULT); playPcm(pcmData); } // 播放PCM音频 private void playPcm(byte[] pcmData) { stopAudioPlayback(); int sampleRate = 16000; int channelConfig = AudioFormat.CHANNEL_OUT_MONO; int audioFormat = AudioFormat.ENCODING_PCM_16BIT; int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat); audioTrack = new AudioTrack( android.media.AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, bufferSize, AudioTrack.MODE_STREAM); audioTrack.play(); audioTrack.write(pcmData, 0, pcmData.length); } // 停止音频播放 private void stopAudioPlayback() { if (audioTrack != null) { if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { audioTrack.stop(); } audioTrack.release(); audioTrack = null; } } // 关闭指定的Socket连接 private void closeSocket(Socket socket) { try { if (socket != null && !socket.isClosed()) { socket.close(); } } catch (IOException e) { Log.w(TAG, "关闭Socket失败", e); } if (socket == clientSocket) { clientSocket = null; synchronized (this) { socketWriter = null; } } } // 关闭服务器Socket private void closeServerSocket() { try { if (serverSocket != null && !serverSocket.isClosed()) { serverSocket.close(); } } catch (IOException e) { Log.w(TAG, "关闭ServerSocket失败", e); } } // Activity销毁时清理资源 @Override protected void onDestroy() { super.onDestroy(); isServerRunning = false; if (ttsEngine != null) { ttsEngine.stop(); ttsEngine.shutdown(); } closeServerSocket(); closeSocket(clientSocket); executorService.shutdownNow(); releaseAudioResources(); stopAudioPlayback(); } // 权限请求结果处理 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "录音权限已授予", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "录音权限被拒绝", Toast.LENGTH_SHORT).show(); } } } public boolean isStopTransmitSent() { return isStopTransmitSent; } public void setStopTransmitSent(boolean stopTransmitSent) { isStopTransmitSent = stopTransmitSent; } } 修改安卓
最新发布
07-02
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qibin01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值