fix: 绑定消息移到MainActivity处理,彻底解决配对失败
与解绑一样,BindFragment的collect可能在MQTT消息到达时还未注册, 导致消息丢失。改为Activity级别统一处理type=2绑定消息。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,8 +7,13 @@ import android.view.View
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.gson.Gson
|
||||
import com.xiaoqu.watch.R
|
||||
import com.xiaoqu.watch.data.device.WatchBindInfo
|
||||
import com.xiaoqu.watch.data.prefs.DevicePrefs
|
||||
import com.xiaoqu.watch.databinding.ActivityMainBinding
|
||||
import com.xiaoqu.watch.network.api.CommonApi
|
||||
import com.xiaoqu.watch.network.safeApiCall
|
||||
import com.xiaoqu.watch.event.AppEvent
|
||||
import com.xiaoqu.watch.event.EventBus
|
||||
import com.xiaoqu.watch.data.prefs.UserPrefs
|
||||
@@ -52,6 +57,9 @@ class MainActivity : AppCompatActivity() {
|
||||
/** NFC 任务打卡管理器 */
|
||||
@Inject lateinit var nfcTaskManager: NfcTaskManager
|
||||
@Inject lateinit var userPrefs: UserPrefs
|
||||
@Inject lateinit var devicePrefs: DevicePrefs
|
||||
@Inject lateinit var commonApi: CommonApi
|
||||
@Inject lateinit var gson: Gson
|
||||
/** OTA 更新弹窗 */
|
||||
lateinit var updateDialog: UpdateDialogView
|
||||
lateinit var notificationBanner: NotificationBannerView
|
||||
@@ -121,6 +129,11 @@ class MainActivity : AppCompatActivity() {
|
||||
notificationBanner.show(count)
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
// 绑定成功 → 存用户信息 → 跳首页
|
||||
Timber.d("MainActivity: 收到绑定消息")
|
||||
handleBindMessage(event.rawJson)
|
||||
}
|
||||
3 -> {
|
||||
// 解绑 → 清除数据 → 跳绑定页(从任何页面都能跳)
|
||||
Timber.d("MainActivity: 收到解绑消息")
|
||||
@@ -229,6 +242,53 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 绑定处理 =====
|
||||
|
||||
/** 防止重复处理绑定消息 */
|
||||
private var bindHandled = false
|
||||
|
||||
/** 处理 MQTT type=2 绑定消息(Activity 级别,不受 Fragment 生命周期影响) */
|
||||
private fun handleBindMessage(rawJson: String) {
|
||||
if (bindHandled) return
|
||||
bindHandled = true
|
||||
|
||||
try {
|
||||
val bindInfo = gson.fromJson(rawJson, WatchBindInfo::class.java)
|
||||
|
||||
// 存入 UserPrefs
|
||||
userPrefs.saveUser(
|
||||
userId = bindInfo.userId,
|
||||
mobile = bindInfo.mobile,
|
||||
userName = bindInfo.userName,
|
||||
headUrl = bindInfo.headUrl
|
||||
)
|
||||
|
||||
// 异步调 API 确认(不阻塞导航)
|
||||
activityScope.launch {
|
||||
try {
|
||||
val params = hashMapOf<String, Any>(
|
||||
"imei" to devicePrefs.imei,
|
||||
"userId" to bindInfo.userId
|
||||
)
|
||||
safeApiCall { commonApi.bindWatchConfirm(params) }
|
||||
Timber.d("MainActivity: 绑定确认 API 已调用")
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "MainActivity: 绑定确认 API 异常")
|
||||
}
|
||||
}
|
||||
|
||||
// 导航到首页
|
||||
val navHost = supportFragmentManager
|
||||
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
||||
navHost.navController.navigate(R.id.action_global_to_home)
|
||||
Timber.d("MainActivity: 绑定成功,已导航到首页")
|
||||
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "MainActivity: 绑定处理异常")
|
||||
bindHandled = false
|
||||
}
|
||||
}
|
||||
|
||||
// ===== OTA 更新 =====
|
||||
|
||||
/** 设置更新弹窗按钮回调 */
|
||||
|
||||
@@ -6,20 +6,14 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.gson.Gson
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.MultiFormatWriter
|
||||
import com.google.zxing.common.BitMatrix
|
||||
import com.xiaoqu.watch.R
|
||||
import com.xiaoqu.watch.data.device.WatchBindInfo
|
||||
import com.xiaoqu.watch.data.prefs.DevicePrefs
|
||||
import com.xiaoqu.watch.data.prefs.UserPrefs
|
||||
import com.xiaoqu.watch.databinding.FragmentBindBinding
|
||||
import com.xiaoqu.watch.event.AppEvent
|
||||
import com.xiaoqu.watch.event.EventBus
|
||||
import com.xiaoqu.watch.network.api.CommonApi
|
||||
import com.xiaoqu.watch.network.safeApiCall
|
||||
import com.xiaoqu.watch.ui.common.BaseFragment
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -36,9 +30,7 @@ import javax.inject.Inject
|
||||
class BindFragment : BaseFragment<FragmentBindBinding>() {
|
||||
|
||||
@Inject lateinit var devicePrefs: DevicePrefs
|
||||
@Inject lateinit var userPrefs: UserPrefs
|
||||
@Inject lateinit var eventBus: EventBus
|
||||
@Inject lateinit var commonApi: CommonApi
|
||||
@Inject lateinit var gson: Gson
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBindBinding {
|
||||
@@ -51,7 +43,8 @@ class BindFragment : BaseFragment<FragmentBindBinding>() {
|
||||
// 生成并显示二维码
|
||||
generateQrCode()
|
||||
|
||||
// 监听 MQTT 绑定消息
|
||||
// 绑定消息由 MainActivity 统一处理(Activity 级别,不受 Fragment 生命周期影响)
|
||||
// 这里只监听用于显示 Loading 状态
|
||||
observeBindEvent()
|
||||
}
|
||||
|
||||
@@ -148,54 +141,10 @@ class BindFragment : BaseFragment<FragmentBindBinding>() {
|
||||
* 3. 调用 bindWatchConfirm API 确认
|
||||
* 4. 导航到首页
|
||||
*/
|
||||
/** 防重复处理标记 */
|
||||
private var bindHandled = false
|
||||
|
||||
/** 收到绑定消息 → 仅切换 Loading 状态(导航由 MainActivity 统一处理) */
|
||||
private fun handleBindSuccess(rawJson: String) {
|
||||
// 防止重复处理(MQTT 可能重发)
|
||||
if (bindHandled) return
|
||||
bindHandled = true
|
||||
|
||||
try {
|
||||
Timber.d("绑定: 收到绑定消息 $rawJson")
|
||||
|
||||
// 切换到配对中状态
|
||||
showLoading()
|
||||
|
||||
// 解析用户信息
|
||||
val bindInfo = gson.fromJson(rawJson, WatchBindInfo::class.java)
|
||||
|
||||
// 存入 UserPrefs
|
||||
userPrefs.saveUser(
|
||||
userId = bindInfo.userId,
|
||||
mobile = bindInfo.mobile,
|
||||
userName = bindInfo.userName,
|
||||
headUrl = bindInfo.headUrl
|
||||
)
|
||||
|
||||
// 调用 API 确认绑定(异步,不阻塞导航)
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
try {
|
||||
val params = hashMapOf<String, Any>(
|
||||
"imei" to devicePrefs.imei,
|
||||
"userId" to bindInfo.userId
|
||||
)
|
||||
safeApiCall { commonApi.bindWatchConfirm(params) }
|
||||
Timber.d("绑定: 确认 API 已调用")
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "绑定: 确认 API 异常,不影响导航")
|
||||
}
|
||||
}
|
||||
|
||||
// 导航到首页(不等 API 返回,用户信息已存本地)
|
||||
findNavController().navigate(R.id.action_bind_to_home)
|
||||
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "绑定: 处理绑定消息异常")
|
||||
bindHandled = false // 异常时允许重试
|
||||
// 异常时恢复二维码显示
|
||||
showQrCode()
|
||||
}
|
||||
Timber.d("绑定: 收到绑定消息,显示 Loading")
|
||||
showLoading()
|
||||
}
|
||||
|
||||
/** 显示二维码状态 */
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
app:destination="@id/bindFragment"
|
||||
app:popUpTo="@id/nav_main" app:popUpToInclusive="true" />
|
||||
|
||||
<!-- 全局 action:绑定成功后从任何页面跳转到首页(清空回退栈) -->
|
||||
<action android:id="@+id/action_global_to_home"
|
||||
app:destination="@id/homeFragment"
|
||||
app:popUpTo="@id/nav_main" app:popUpToInclusive="true" />
|
||||
|
||||
<!-- 启动分发页 -->
|
||||
<fragment
|
||||
android:id="@+id/splashFragment"
|
||||
|
||||
Reference in New Issue
Block a user