优化重连(补)
authorxue <2144439972@qq.com>
Thu, 25 Dec 2025 02:47:11 +0000 (10:47 +0800)
committerxue <2144439972@qq.com>
Thu, 25 Dec 2025 02:47:11 +0000 (10:47 +0800)
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdMainView.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdModel.cpp
code/sdk/application/wearable/ln/nativeapp/nativeui/thunderbird/src/ThunderBirdPresenter.cpp

index 6e91025..27319b0 100644 (file)
@@ -335,16 +335,28 @@ namespace OHOS
                 delete chargeBatteryicon;
                 chargeBatteryicon = nullptr;
             }
-            if (listenIcon != nullptr)
-            {
-                delete listenIcon;
-                listenIcon = nullptr;
+        if (listenIcon != nullptr)
+        {
+            delete listenIcon;
+            listenIcon = nullptr;
+        }
+        
+        // 最后删除group1
+        delete group1;
+        group1 = nullptr;
+        
+        // 清理最后一帧视图
+        if (lastFrameView_ != nullptr)
+        {
+            // 先从父组件中移除
+            if (ScrollView_ != nullptr) {
+                ScrollView_->Remove(lastFrameView_);
             }
-            
-            // 最后删除group1
-            delete group1;
-            group1 = nullptr;
+            delete lastFrameView_;
+            lastFrameView_ = nullptr;
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::DeInit: Destroyed lastFrameView_");
         }
+    }
 
         // 清理其他成员变量
         video_ = nullptr;
@@ -397,6 +409,17 @@ namespace OHOS
             backGroundView->SetPosition(0, 0, 360, 360);
             backGroundView->SetStyle(STYLE_BACKGROUND_COLOR, 0xff000000);
             backGroundView->SetStyle(STYLE_BACKGROUND_OPA, 0xD0);
+            
+            // 创建最后一帧视图(只创建一次,不销毁,避免频繁创建销毁)
+            lastFrameView_ = new UIImageView();
+            if (lastFrameView_ != nullptr)
+            {
+                lastFrameView_->SetAutoEnable(false);
+                lastFrameView_->SetResizeMode(UIImageView::COVER);
+                lastFrameView_->SetVisible(false); // 初始状态为隐藏
+                ScrollView_->Add(lastFrameView_);
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::OnStart: Created lastFrameView_");
+            }
             //backGroundView->SetVisible(false);
             ScrollView_->Add(backGroundView);
 
@@ -454,7 +477,9 @@ namespace OHOS
         }
         if (g_isSwitchingVideo)
         {
-            WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::WaitForVideoSwitchComplete: Timeout after %d ms, video switch still in progress", maxWaitMs);
+            WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::WaitForVideoSwitchComplete: Timeout after %d ms, video switch still in progress, force reset flag", maxWaitMs);
+            // 超时后强制重置标志位,避免死锁
+            g_isSwitchingVideo = false;
             return false;
         }
         return true;
@@ -579,31 +604,23 @@ namespace OHOS
                 WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Captured last frame, size: %dx%d", 
                              lastFrameImage.header.width, lastFrameImage.header.height);
                 
-                // 创建或更新临时视图显示最后一帧
-                if (lastFrameView_ == nullptr)
-                {
-                    lastFrameView_ = new UIImageView();
-                    if (lastFrameView_ != nullptr)
-                    {
-                        lastFrameView_->SetPosition(surfaceRect.GetX(), surfaceRect.GetY(), 
-                                                    surfaceRect.GetWidth(), surfaceRect.GetHeight());
-                        lastFrameView_->SetAutoEnable(false);
-                        lastFrameView_->SetResizeMode(UIImageView::COVER);
-                        // 将临时视图添加到surfaceView_的父容器中,并放在surfaceView_上方
-                        if (ScrollView_ != nullptr)
-                        {
-                            ScrollView_->Add(lastFrameView_);
-                        }
-                    }
-                }
-                
+                // 更新最后一帧视图的位置和内容(视图已在初始化时创建,只需刷新)
                 if (lastFrameView_ != nullptr)
                 {
+                    // 更新位置和大小
+                    lastFrameView_->SetPosition(surfaceRect.GetX(), surfaceRect.GetY(), 
+                                                surfaceRect.GetWidth(), surfaceRect.GetHeight());
+                    // 更新图片内容
                     lastFrameView_->SetSrc(&lastFrameImage);
+                    // 显示视图
                     lastFrameView_->SetVisible(true);
                     lastFrameView_->Invalidate();
                     WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Last frame view displayed");
                 }
+                else
+                {
+                    WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: lastFrameView_ is null, cannot display last frame");
+                }
             }
             else
             {
@@ -611,34 +628,28 @@ namespace OHOS
             }
         }
 
-        // 步骤2:在创建新播放器前,停止并销毁旧播放器
-        // 静态图片会遮挡整个过程,所以可以安全地销毁旧播放器
-        if (oldPlayer != nullptr)
-        {
-            // 先停止播放
-            if (oldWasEntered || oldWasPlaying)
-            {
-                oldPlayer->StopVideoPlay();
-            }
-            // 等待旧播放器完全停止
-            usleep(50000); // 50ms,确保旧播放器完全停止
-            delete oldPlayer;
-            oldPlayer = nullptr;
-            videoPlay_ = nullptr; // 清除指针
-            g_videoPlay = nullptr;
-            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Old player stopped and destroyed before creating new player");
-        }
-
-        // 步骤3:创建新播放器
+        // 步骤2:创建新播放器(不销毁旧播放器,保留作为备用)
         newPlayer = new MediaVideoPlay(surface, nullptr, targetPath, true);
         if (newPlayer == nullptr)
         {
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Failed to create MediaVideoPlay");
+            // 创建失败,恢复旧播放器,
+            if (oldPlayer != nullptr && oldWasPlaying)
+            {
+                oldPlayer->ResumeVideoPlay();
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player creation failed, resumed old player");
+                if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+                {
+                    lastFrameView_->SetVisible(false);
+                    lastFrameView_->Invalidate();
+                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Hidden last frame view, old player resumed");
+                }
+            }
             g_isSwitchingVideo = false;
             return false;
         }
 
-        // 步骤4:立即启动新播放器
+        // 步骤3:启动新播放器
         int32_t ret = newPlayer->StartVideoPlay();
         if (ret != 0)
         {
@@ -646,23 +657,37 @@ namespace OHOS
             delete newPlayer;
             newPlayer = nullptr;
             
-            // 如果启动失败,保持lastFrameView可见,避免黑屏
-            if (lastFrameView_ != nullptr && lastFrameView_->IsVisible()) {
+            // 启动失败,恢复旧播放器
+            if (oldPlayer != nullptr && oldWasPlaying)
+            {
+                oldPlayer->ResumeVideoPlay();
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player start failed, resumed old player");
+                // 隐藏最后一帧视图,因为旧播放器会继续播放
+                if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+                {
+                    lastFrameView_->SetVisible(false);
+                    lastFrameView_->Invalidate();
+                }
+                // 释放截图内存(视图已隐藏,不再需要)
+                if (hasLastFrame && lastFrameImage.data != nullptr)
+                {
+                    ImageCacheFree(lastFrameImage);
+                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (start failed)");
+                }
+            }
+            else if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+            {
+                // 如果没有旧播放器,保持lastFrameView可见,避免黑屏
+                // 此时不释放内存,因为视图还在使用
                 WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player failed to start, keeping last frame view visible to avoid black screen");
-            } else {
-                // 如果没有lastFrameView,尝试切换到默认表情,避免黑屏
-                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player failed to start and no last frame view, attempting to switch to default winking");
-                if (ThunderBirdModel::GetInstance()) {
-                    std::string defaultPath = "/user/res/video/CloseEyes/round-eyes/amber.mp4";
-                    if (access(defaultPath.c_str(), F_OK) == 0) {
-                        // 延迟切换,避免递归调用
-                        GraphicService::GetInstance()->PostGraphicEvent(
-                            [defaultPath]() {
-                                if (ThunderBirdMainView::GetInstance()) {
-                                    ThunderBirdMainView::GetInstance()->SwitchVideo(defaultPath.c_str());
-                                }
-                            });
-                    }
+            }
+            else
+            {
+                // 如果没有视图显示,释放内存
+                if (hasLastFrame && lastFrameImage.data != nullptr)
+                {
+                    ImageCacheFree(lastFrameImage);
+                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (no view visible)");
                 }
             }
             
@@ -670,123 +695,164 @@ namespace OHOS
             return false;
         }
 
-        // 步骤5:立即切换指针到新播放器
-        videoPlay_ = newPlayer;
-        g_videoPlay = videoPlay_;
+        // 步骤4:等待并检查新播放器是否正常播放
+        int checkCount = 0;
+        const int maxCheckCount = 50; // 50 * 20ms = 1000ms
+        bool newPlayerPlaying = false;
+        bool newPlayerError = false;
         
-        // 步骤5.5:同步等待新播放器渲染第一帧后再隐藏最后一帧视图
-        // 静态图片会一直遮挡,直到新播放器的第一帧真正渲染到屏幕
-        // 通过检查Surface的buffer状态来判断第一帧是否已渲染
-        if (lastFrameView_ != nullptr && lastFrameView_->IsVisible() && surface != nullptr)
-        {
-            // 等待新播放器开始播放
-            int checkCount = 0;
-            const int maxCheckCount = 50; // 50 * 20ms = 1000ms
-            bool playerConfirmed = false;
-            
-            while (checkCount < maxCheckCount)
+        while (checkCount < maxCheckCount)
+        {
+            // 检查新播放器是否真正开始播放
+            if (newPlayer != nullptr && newPlayer->isEntered_ && newPlayer->isPlayed_ && !newPlayer->isPause_)
             {
-                // 检查新播放器是否真正开始播放
-                if (newPlayer != nullptr && newPlayer->isEntered_ && newPlayer->isPlayed_ && !newPlayer->isPause_)
-                {
-                    playerConfirmed = true;
-                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player confirmed playing after %d ms", checkCount * 20);
-                    break;
-                }
-                usleep(20000); // 等待20ms
-                checkCount++;
+                newPlayerPlaying = true;
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player confirmed playing after %d ms", checkCount * 20);
+                break;
             }
-            
-            // 如果新播放器已开始播放,检查Surface是否有新的buffer(表示第一帧已输出)
-            bool canHideLastFrame = false; // 是否可以安全隐藏最后一帧视图
-            if (playerConfirmed)
-            {
-                // 检查Surface是否有新的buffer被flush(表示第一帧已经输出到Surface)
-                // 通过检查GetBackBuf()来判断是否有新的buffer
-                LiteSurface* liteSurface = dynamic_cast<LiteSurface*>(surface);
-                if (liteSurface != nullptr)
+            // 检查新播放器是否发生错误
+            if (newPlayer != nullptr && newPlayer->playError_)
+            {
+                newPlayerError = true;
+                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player error detected after %d ms", checkCount * 20);
+                break;
+            }
+            usleep(20000); // 等待20ms
+            checkCount++;
+        }
+        
+        // 步骤5:根据新播放器状态决定后续操作
+        if (newPlayerPlaying && !newPlayerError)
+        {
+            // 新播放器正常播放,检查第一帧是否已输出
+            bool firstFrameReady = false;
+            LiteSurface* liteSurface = dynamic_cast<LiteSurface*>(surface);
+            if (liteSurface != nullptr)
+            {
+                int bufferCheckCount = 0;
+                const int maxBufferCheckCount = 30; // 30 * 50ms = 1500ms
+                
+                while (bufferCheckCount < maxBufferCheckCount)
                 {
-                    int bufferCheckCount = 0;
-                    const int maxBufferCheckCount = 30; // 30 * 50ms = 1500ms
-                    bool firstFrameReady = false;
-                    
-                    while (bufferCheckCount < maxBufferCheckCount)
-                    {
-                        // 检查Surface是否有新的buffer(GetBackBuf返回非null表示有新的buffer)
-                        SurfaceBuffer* backBuf = liteSurface->GetBackBuf();
-                        if (backBuf != nullptr)
-                        {
-                            // 有新的buffer,说明第一帧已经输出到Surface
-                            firstFrameReady = true;
-                            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: First frame buffer ready after %d ms", bufferCheckCount * 50);
-                            // 再等待一小段时间确保第一帧已经渲染到屏幕
-                            usleep(50000); // 50ms,确保第一帧已渲染到屏幕
-                            break;
-                        }
-                        usleep(50000); // 等待50ms
-                        bufferCheckCount++;
-                    }
-                    
-                    if (firstFrameReady)
+                    SurfaceBuffer* backBuf = liteSurface->GetBackBuf();
+                    if (backBuf != nullptr)
                     {
-                        // 第一帧已就绪,可以安全隐藏最后一帧视图
-                        canHideLastFrame = true;
+                        firstFrameReady = true;
+                        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: First frame buffer ready after %d ms", bufferCheckCount * 50);
+                        usleep(50000); // 50ms,确保第一帧已渲染到屏幕
+                        break;
                     }
-                    else
-                    {
-                        // 第一帧未就绪,保留最后一帧视图,避免黑屏
-                        WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: First frame buffer not ready after %d ms, keeping last frame view to avoid black screen", maxBufferCheckCount * 50);
-                    }
-                }
-                else
-                {
-                    // 如果不是LiteSurface,使用固定等待时间
-                    usleep(300000); // 300ms
-                    // 等待后认为可以安全隐藏最后一帧视图
-                    canHideLastFrame = true;
+                    usleep(50000); // 等待50ms
+                    bufferCheckCount++;
                 }
             }
             else
             {
-                // 新播放器未确认播放,保留最后一帧视图,避免黑屏
-                WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player not confirmed playing after %d ms, keeping last frame view to avoid black screen", maxCheckCount * 20);
+                // 如果不是LiteSurface,使用固定等待时间
+                usleep(300000); // 300ms
+                firstFrameReady = true;
             }
             
-            // 只有在确认新播放器已开始播放且第一帧已就绪时,才隐藏最后一帧视图
-            // 这样可以避免黑屏问题
-            if (canHideLastFrame && lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+            // 新播放器正常播放,停止并销毁旧播放器
+            if (oldPlayer != nullptr)
             {
-                lastFrameView_->SetVisible(false);
-                lastFrameView_->Invalidate();
-                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Hidden last frame view, new player first frame should be rendered");
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player playing successfully, destroying old player");
+                if (oldWasEntered || oldWasPlaying)
+                {
+                    oldPlayer->StopVideoPlay();
+                }
+                // 等待旧播放器完全停止
+                usleep(50000); // 50ms,确保旧播放器完全停止
+                delete oldPlayer;
+                oldPlayer = nullptr;
             }
-            else if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+            
+            // 更新指针到新播放器
+            videoPlay_ = newPlayer;
+            g_videoPlay = videoPlay_;
+            
+            // 隐藏最后一帧视图
+            if (firstFrameReady && lastFrameView_ != nullptr && lastFrameView_->IsVisible())
             {
-                // 不能安全隐藏最后一帧视图,保留显示,避免黑屏
-                WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Keeping last frame view visible to avoid black screen");
+                usleep(200000); // 200ms
+                lastFrameView_->SetVisible(false);
+                lastFrameView_->Invalidate();
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Hidden last frame view, new player first frame rendered");
             }
             
-            // 释放最后一帧截图的内存(在隐藏静态图片后释放)
+            // 更新当前播放的视频路径
+            currentVideoPath_ = targetPath;
+            
+            // 释放最后一帧截图的内存
             if (hasLastFrame && lastFrameImage.data != nullptr)
             {
                 ImageCacheFree(lastFrameImage);
                 WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory");
             }
+            
+            // 清除切换视频标志
+            g_isSwitchingVideo = false;
+            
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Successfully switched to video: %s", uri);
+            return true;
         }
-        else if (hasLastFrame && lastFrameImage.data != nullptr)
+        else
         {
-            // 如果没有静态图片视图,直接释放截图内存
-            ImageCacheFree(lastFrameImage);
+            // 新播放器未正常播放,销毁新播放器并恢复旧播放器
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player not playing correctly, destroying new player and resuming old player");
+            
+            // 停止并销毁新播放器
+            if (newPlayer != nullptr)
+            {
+                if (newPlayer->isEntered_)
+                {
+                    newPlayer->StopVideoPlay();
+                }
+                usleep(50000); // 50ms,确保新播放器完全停止
+                delete newPlayer;
+                newPlayer = nullptr;
+            }
+            
+            // 恢复旧播放器
+            if (oldPlayer != nullptr && oldWasPlaying)
+            {
+                oldPlayer->ResumeVideoPlay();
+                WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Resumed old player");
+                // 隐藏最后一帧视图,因为旧播放器会继续播放
+                if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+                {
+                    lastFrameView_->SetVisible(false);
+                    lastFrameView_->Invalidate();
+                }
+                // 释放截图内存(视图已隐藏,不再需要)
+                if (hasLastFrame && lastFrameImage.data != nullptr)
+                {
+                    ImageCacheFree(lastFrameImage);
+                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (resumed old player)");
+                }
+            }
+            else if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+            {
+                // 如果没有旧播放器,保持lastFrameView可见,避免黑屏
+                // 此时不释放内存,因为视图还在使用
+                WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: No old player to resume, keeping last frame view visible");
+            }
+            else
+            {
+                // 如果没有视图显示,释放内存
+                if (hasLastFrame && lastFrameImage.data != nullptr)
+                {
+                    ImageCacheFree(lastFrameImage);
+                    WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (no view visible)");
+                }
+            }
+            
+            // 清除切换视频标志
+            g_isSwitchingVideo = false;
+            
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Failed to switch video, old player resumed: %s", uri);
+            return false;
         }
-        
-        // 更新当前播放的视频路径
-        currentVideoPath_ = targetPath;
-        
-        // 清除切换视频标志
-        g_isSwitchingVideo = false;
-        
-        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Successfully switched to video: %s", uri);
-        return true;
     }
 
     void ThunderBirdMainView::CloseVideo() // 关闭表情接口
@@ -1928,3 +1994,4 @@ namespace OHOS
         return;
     }
 }
+
index 0032b75..c1bd8f4 100644 (file)
@@ -22,7 +22,7 @@
  #include "thunderbird/include/ThunderBirdBlueView.h"
  #include "thunderbird/include/ThunderBirdPresenter.h"
  #include "thunderbird/include/ThunderBirdAdjustView.h"
- #include "bluetooth/BluetoothModel.h"
+  #include "bluetooth/BluetoothModel.h"
  #include "wearable_log.h"
  #include <sys/time.h>
  #include <service/graphic_service.h>
@@ -31,6 +31,7 @@
 #include "bluetooth/Ln_Bluetooth_apiC.h"
 #include <algorithm>
 #include <ctime>
+#include <memory>
 #include "custom_runtime.h"
 #ifdef SUPPORT_BATTERY_SERVICE
 #include "battery_hal.h"
@@ -1790,12 +1791,13 @@ extern "C" {
                             view->ChangeView(currentView, THUNDERBIRD_GUIDEVIEW, ThunderBirdGuideView::THUNDERBIRD_GUIDEVIEW_5);
                         }
                         ThunderBirdDialogueView::GetInstance()->DialogueFirst = true;
+                        // 先设置退出标志,防止录音结束回调误判为正常录音结束
+                        ThunderBirdPresenter::GetInstance()->SetDialogueing(false);
                         ln_ws_end_audio_chat();//结束对话
                         AI_ForceInterrupt();
                         ln_ws_send_voice_chat_interrupt("退出对话");
                         do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_AUDIO_DEINIT, NULL, 0);
                         ThunderBirdModel::GetInstance()->OnExitDialogueMode();
-                        ThunderBirdPresenter::GetInstance()->SetDialogueing(false);
                     }
                      
                     // 检查是否是网络连接中界面,6秒后自动跳转到状态界面
@@ -1813,7 +1815,7 @@ extern "C" {
                             if (!networkSuccess) {
                                 // 网络仍未连接,检查是否超过60秒
                                 m_networkConnectingTimeoutCount++;
-                                if (m_networkConnectingTimeoutCount < 10) {  // 最多10次,共60秒
+                                if (m_networkConnectingTimeoutCount < 5) {  // 最多10次,共60秒
                                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "网络仍未连接,继续等待(%d/10)", m_networkConnectingTimeoutCount);
                                     shouldContinue = true;
                                     // 重新启动6秒定时器
@@ -1839,7 +1841,7 @@ extern "C" {
                             if (!vadAuthSuccess) {
                                 // VAD认证仍未成功,检查是否超过60秒
                                 m_networkConnectingTimeoutCount++;
-                                if (m_networkConnectingTimeoutCount < 10) {  // 最多10次,共60秒
+                                if (m_networkConnectingTimeoutCount < 5) {  // 最多10次,共60秒
                                     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "VAD认证仍未成功,继续等待(%d/10)", m_networkConnectingTimeoutCount);
                                     shouldContinue = true;
                                     // 重新启动6秒定时器
@@ -2631,12 +2633,15 @@ extern "C" {
        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpression: switching to %s", expressionPath.c_str());
        // 通过图形服务调用 ThunderBirdMainView 的 SwitchVideo 函数
        // 注意:PostGraphicEvent 是异步的,这里直接返回 true 表示调用已提交
+       // 使用 shared_ptr 确保字符串生命周期,避免 lambda 执行时对象已销毁
+       auto pathPtr = std::make_shared<std::string>(expressionPath);
        GraphicService::GetInstance()->PostGraphicEvent(
-           [expressionPath]() {
-               if (ThunderBirdMainView::GetInstance()) {
-                   ThunderBirdMainView::GetInstance()->SwitchVideo(expressionPath.c_str());
+           [pathPtr]() {
+               ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+               if (mainView != nullptr && pathPtr != nullptr) {
+                   mainView->SwitchVideo(pathPtr->c_str());
                } else {
-                   WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpression: ThunderBirdMainView instance is null");
+                   WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpression: ThunderBirdMainView instance is null or path invalid");
                }
            });
        
@@ -2700,14 +2705,23 @@ extern "C" {
         {
             WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Video switch in progress, waiting for completion...");
             // 在图形线程中等待,避免阻塞当前线程
+            // 使用 shared_ptr 确保字符串生命周期,避免 lambda 执行时对象已销毁
+            auto pathPtr = std::make_shared<std::string>(normalizedPath);
             GraphicService::GetInstance()->PostGraphicEvent(
-                [normalizedPath]() {
+                [pathPtr]() {
                     // 等待之前的切换完成
-                    if (ThunderBirdMainView::GetInstance()) {
+                    ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+                    if (mainView != nullptr) {
                         ThunderBirdMainView::WaitForVideoSwitchComplete(2000);
                         // 再次检查是否还在切换(防止超时后仍在切换)
                         if (!ThunderBirdMainView::IsSwitchingVideo()) {
-                            ThunderBirdMainView::GetInstance()->SwitchVideo(normalizedPath.c_str());
+                            // 再次检查对象有效性,防止在执行过程中被销毁
+                            ThunderBirdMainView* view = ThunderBirdMainView::GetInstance();
+                            if (view != nullptr && pathPtr != nullptr) {
+                                view->SwitchVideo(pathPtr->c_str());
+                            } else {
+                                WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Object invalidated during execution");
+                            }
                         } else {
                             WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: Video switch still in progress after wait, skipping this switch");
                         }
@@ -2718,12 +2732,15 @@ extern "C" {
         } else {
             // 通过图形服务调用 ThunderBirdMainView 的 SwitchVideo 函数
             // 注意:PostGraphicEvent 是异步的,这里直接返回 true 表示调用已提交
+            // 使用 shared_ptr 确保字符串生命周期,避免 lambda 执行时对象已销毁
+            auto pathPtr = std::make_shared<std::string>(normalizedPath);
             GraphicService::GetInstance()->PostGraphicEvent(
-                [normalizedPath]() {
-                    if (ThunderBirdMainView::GetInstance()) {
-                        ThunderBirdMainView::GetInstance()->SwitchVideo(normalizedPath.c_str());
+                [pathPtr]() {
+                    ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+                    if (mainView != nullptr && pathPtr != nullptr) {
+                        mainView->SwitchVideo(pathPtr->c_str());
                     } else {
-                        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView instance is null");
+                        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::SwitchExpressionVideo: ThunderBirdMainView instance is null or path invalid");
                     }
                 });
         }
@@ -3195,6 +3212,13 @@ extern "C" {
         // return ;//需要vad的时候在处理
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioRecordingEnd: 录音结束");
         
+        // 检查是否正在退出对话模式,如果是则不应该跳转到播放界面
+        ThunderBirdPresenter* presenter = ThunderBirdPresenter::GetInstance();
+        if (presenter != nullptr && !presenter->isDialogueing) {
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioRecordingEnd: 正在退出对话模式,忽略录音结束事件");
+            return;
+        }
+        
         // 取消退出对话的定时器(用户结束录音,说明要继续对话)
         StopCountUpTimer();
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::HandleAudioRecordingEnd: 取消退出对话定时器");
@@ -3390,6 +3414,8 @@ extern "C" {
          WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterDialogueMode: 记录时间线表情: %s", m_currentExpression.c_str());
         // 重置对话模式finished标志
         m_dialogueModeFinished = false;
+        // 设置标志位,表示在对话模式中
+        m_needGetTimelineExpression = true;
         
         // 等待视频切换完成,避免在视频切换过程中切换表情导致冲突
         if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::IsSwitchingVideo()) {
@@ -3434,63 +3460,16 @@ extern "C" {
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 开始退出对话模式");
         
         // 隐藏小绿点
-        if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::GetInstance()->listenIcon) {
-            ThunderBirdMainView::GetInstance()->listenIcon->SetVisible(false);
+        ThunderBirdMainView* mainView = ThunderBirdMainView::GetInstance();
+        if (mainView != nullptr && mainView->listenIcon != nullptr) {
+            mainView->listenIcon->SetVisible(false);
         }
         // 重置对话模式finished标志
         m_dialogueModeFinished = false;
         
-        // 等待视频切换完成,避免在视频切换过程中恢复表情导致冲突
-        if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::IsSwitchingVideo()) {
-            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 等待视频切换完成");
-            ThunderBirdMainView::WaitForVideoSwitchComplete(2000);
-        }
-        
-        // 恢复到进入对话模式前记录的时间线表情
-        if (!m_currentExpression.empty()) {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 恢复时间线表情: %s", m_dialogueExpression.c_str());
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 当前表情: %s", m_currentExpression.c_str());
-            //如果相同直接返回
-            if(m_dialogueExpression == m_currentExpression)     
-            {
-                return;
-            }
-            // 恢复表情状态
-            // 构建表情文件路径并切换表情
-            std::string expressionPath;
-            if (screenImageAsEmoji_ == false) {
-                // 不为屏保模式,根据角色配置构建表情路径
-                if (eyesColor_.empty() || eyesShape_.empty() || 
-                    (eyesShape_ == "calm-eyes" && eyesColor_ == "amber")) {
-                    // 默认表情
-                    std::string emotionFileName = MapEmotionToFileName(m_currentExpression.c_str());
-                    expressionPath = "/user/res/video/Default/" + emotionFileName + ".mp4";
-                } else {
-                    // 非默认表情
-                    if (m_currentExpression == "winking") {
-                        // 眨眼表情
-                        expressionPath = "/user/res/video/CloseEyes/" + eyesShape_ + "/" + eyesColor_ + ".mp4";
-                    } else if (m_currentExpression == "sleeping") {
-                        // 睡眠表情
-                        expressionPath = "/user/res/video/Default/sleeping.mp4";
-                    } else {
-                        // 其他表情
-                        expressionPath = "/user/userdata/leiniao/emoji/" + eyesShape_ + "/" + eyesColor_ + "/" + m_currentExpression + ".mp4";
-                    }
-                }
-                
-                // 检查文件是否存在并切换表情
-                if (access(expressionPath.c_str(), F_OK) == 0) {
-                    SwitchExpressionVideo(expressionPath.c_str());
-                    HandleHairIconChange(m_currentExpression);
-                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 恢复表情成功: %s", expressionPath.c_str());
-                } else {
-                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 表情文件不存在: %s", expressionPath.c_str());
-                }
-            }
-        } else {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 没有记录的表情,无法恢复");
-        }
+        // 不在这里切换表情,标志位保持为1,在发呆中界面时获取时间线表情
+        // m_needGetTimelineExpression 保持为 true,表示需要获取时间线表情
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitDialogueMode: 退出对话模式,标志位保持为true,将在发呆中界面获取时间线表情");
     }
     
     // 进入哄睡模式时记录当前表情(进入THUNDERBIRD_LULLABYVIEW_4时调用)
@@ -3499,6 +3478,8 @@ extern "C" {
         // 记录进入哄睡模式前的时间线表情(用于退出时恢复)
         m_lullabyExpression = "winking";
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnEnterLullabyMode: 记录时间线表情: %s", m_currentExpression.c_str());
+        // 设置标志位,表示在哄睡模式中
+        m_needGetTimelineExpression = true;
         //如果本来就是眨眼的表情直接返回
         if (m_currentExpression == "winking" || m_currentExpression.empty() == true) {
             return;
@@ -3534,50 +3515,10 @@ extern "C" {
         if (ThunderBirdMainView::GetInstance() && ThunderBirdMainView::GetInstance()->listenIcon) {
             ThunderBirdMainView::GetInstance()->listenIcon->SetVisible(false);
         }
-        // 恢复到进入哄睡模式前记录的时间线表情
-        if (!m_lullabyExpression.empty()) {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitLullabyMode: 恢复时间线表情: %s", m_lullabyExpression.c_str());
-            //如果相同直接返回
-            if(m_currentExpression.empty() == true ||m_currentExpression == "winking")     
-            {
-                return;
-            }
-            // 恢复表情状态
-            // 构建表情文件路径并切换表情
-            std::string expressionPath;
-            if (screenImageAsEmoji_ == false) {
-                // 不为屏保模式,根据角色配置构建表情路径
-                if (eyesColor_.empty() || eyesShape_.empty() || 
-                    (eyesShape_ == "calm-eyes" && eyesColor_ == "amber")) {
-                    // 默认表情
-                    std::string emotionFileName = MapEmotionToFileName(m_currentExpression.c_str());
-                    expressionPath = "/user/res/video/Default/" + emotionFileName + ".mp4";
-                } else {
-                    // 非默认表情
-                    if (m_currentExpression == "winking") {
-                        // 眨眼表情
-                        expressionPath = "/user/res/video/CloseEyes/" + eyesShape_ + "/" + eyesColor_ + ".mp4";
-                    } else if (m_currentExpression == "sleeping") {
-                        // 睡眠表情
-                        expressionPath = "/user/res/video/Default/sleeping.mp4";
-                    } else {
-                        // 其他表情
-                        expressionPath = "/user/userdata/leiniao/emoji/" + eyesShape_ + "/" + eyesColor_ + "/" + m_currentExpression + ".mp4";
-                    }
-                }
-                
-                // 检查文件是否存在并切换表情
-                if (access(expressionPath.c_str(), F_OK) == 0) {
-                    SwitchExpressionVideo(expressionPath.c_str());
-                    HandleHairIconChange(m_currentExpression);
-                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitLullabyMode: 恢复表情成功: %s", expressionPath.c_str());
-                } else {
-                    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitLullabyMode: 表情文件不存在: %s", expressionPath.c_str());
-                }
-            }
-        } else {
-            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitLullabyMode: 没有记录的表情,无法恢复");
-        }
+        
+        // 不在这里切换表情,标志位保持为1,在发呆中界面时获取时间线表情
+        // m_needGetTimelineExpression 保持为 true,表示需要获取时间线表情
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdModel::OnExitLullabyMode: 退出哄睡模式,标志位保持为true,将在发呆中界面获取时间线表情");
     }
     
     // 设置当前表情状态
index 648b62b..9798749 100644 (file)
@@ -1231,12 +1231,14 @@ namespace OHOS
                     ThunderBirdMainView::WaitForVideoSwitchComplete(2000);
                 }
                 
+                // 先设置退出标志,防止录音结束回调误判为正常录音结束
+                isDialogueing = false;
+                
                 ln_ws_end_audio_chat();//结束对话
                 
                 // 退出对话模式时恢复表情
                 AI_ForceInterrupt();
                 ln_ws_send_voice_chat_interrupt("退出对话");
-                isDialogueing = false;
                 
                 // 检查绑定状态,如果未绑定则跳转到 THUNDERBIRD_GUIDEVIEW_5
                 if (!ThunderBirdModel::GetInstance()->getbind_status()) {