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.navigation.fragment.NavHostFragment
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.xiaoqu.watch.R
|
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.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.AppEvent
|
||||||
import com.xiaoqu.watch.event.EventBus
|
import com.xiaoqu.watch.event.EventBus
|
||||||
import com.xiaoqu.watch.data.prefs.UserPrefs
|
import com.xiaoqu.watch.data.prefs.UserPrefs
|
||||||
@@ -52,6 +57,9 @@ class MainActivity : AppCompatActivity() {
|
|||||||
/** NFC 任务打卡管理器 */
|
/** NFC 任务打卡管理器 */
|
||||||
@Inject lateinit var nfcTaskManager: NfcTaskManager
|
@Inject lateinit var nfcTaskManager: NfcTaskManager
|
||||||
@Inject lateinit var userPrefs: UserPrefs
|
@Inject lateinit var userPrefs: UserPrefs
|
||||||
|
@Inject lateinit var devicePrefs: DevicePrefs
|
||||||
|
@Inject lateinit var commonApi: CommonApi
|
||||||
|
@Inject lateinit var gson: Gson
|
||||||
/** OTA 更新弹窗 */
|
/** OTA 更新弹窗 */
|
||||||
lateinit var updateDialog: UpdateDialogView
|
lateinit var updateDialog: UpdateDialogView
|
||||||
lateinit var notificationBanner: NotificationBannerView
|
lateinit var notificationBanner: NotificationBannerView
|
||||||
@@ -121,6 +129,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
notificationBanner.show(count)
|
notificationBanner.show(count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2 -> {
|
||||||
|
// 绑定成功 → 存用户信息 → 跳首页
|
||||||
|
Timber.d("MainActivity: 收到绑定消息")
|
||||||
|
handleBindMessage(event.rawJson)
|
||||||
|
}
|
||||||
3 -> {
|
3 -> {
|
||||||
// 解绑 → 清除数据 → 跳绑定页(从任何页面都能跳)
|
// 解绑 → 清除数据 → 跳绑定页(从任何页面都能跳)
|
||||||
Timber.d("MainActivity: 收到解绑消息")
|
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 更新 =====
|
// ===== OTA 更新 =====
|
||||||
|
|
||||||
/** 设置更新弹窗按钮回调 */
|
/** 设置更新弹窗按钮回调 */
|
||||||
|
|||||||
@@ -6,20 +6,14 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.zxing.BarcodeFormat
|
import com.google.zxing.BarcodeFormat
|
||||||
import com.google.zxing.MultiFormatWriter
|
import com.google.zxing.MultiFormatWriter
|
||||||
import com.google.zxing.common.BitMatrix
|
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.DevicePrefs
|
||||||
import com.xiaoqu.watch.data.prefs.UserPrefs
|
|
||||||
import com.xiaoqu.watch.databinding.FragmentBindBinding
|
import com.xiaoqu.watch.databinding.FragmentBindBinding
|
||||||
import com.xiaoqu.watch.event.AppEvent
|
import com.xiaoqu.watch.event.AppEvent
|
||||||
import com.xiaoqu.watch.event.EventBus
|
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 com.xiaoqu.watch.ui.common.BaseFragment
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -36,9 +30,7 @@ import javax.inject.Inject
|
|||||||
class BindFragment : BaseFragment<FragmentBindBinding>() {
|
class BindFragment : BaseFragment<FragmentBindBinding>() {
|
||||||
|
|
||||||
@Inject lateinit var devicePrefs: DevicePrefs
|
@Inject lateinit var devicePrefs: DevicePrefs
|
||||||
@Inject lateinit var userPrefs: UserPrefs
|
|
||||||
@Inject lateinit var eventBus: EventBus
|
@Inject lateinit var eventBus: EventBus
|
||||||
@Inject lateinit var commonApi: CommonApi
|
|
||||||
@Inject lateinit var gson: Gson
|
@Inject lateinit var gson: Gson
|
||||||
|
|
||||||
override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBindBinding {
|
override fun createBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentBindBinding {
|
||||||
@@ -51,7 +43,8 @@ class BindFragment : BaseFragment<FragmentBindBinding>() {
|
|||||||
// 生成并显示二维码
|
// 生成并显示二维码
|
||||||
generateQrCode()
|
generateQrCode()
|
||||||
|
|
||||||
// 监听 MQTT 绑定消息
|
// 绑定消息由 MainActivity 统一处理(Activity 级别,不受 Fragment 生命周期影响)
|
||||||
|
// 这里只监听用于显示 Loading 状态
|
||||||
observeBindEvent()
|
observeBindEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,54 +141,10 @@ class BindFragment : BaseFragment<FragmentBindBinding>() {
|
|||||||
* 3. 调用 bindWatchConfirm API 确认
|
* 3. 调用 bindWatchConfirm API 确认
|
||||||
* 4. 导航到首页
|
* 4. 导航到首页
|
||||||
*/
|
*/
|
||||||
/** 防重复处理标记 */
|
/** 收到绑定消息 → 仅切换 Loading 状态(导航由 MainActivity 统一处理) */
|
||||||
private var bindHandled = false
|
|
||||||
|
|
||||||
private fun handleBindSuccess(rawJson: String) {
|
private fun handleBindSuccess(rawJson: String) {
|
||||||
// 防止重复处理(MQTT 可能重发)
|
Timber.d("绑定: 收到绑定消息,显示 Loading")
|
||||||
if (bindHandled) return
|
|
||||||
bindHandled = true
|
|
||||||
|
|
||||||
try {
|
|
||||||
Timber.d("绑定: 收到绑定消息 $rawJson")
|
|
||||||
|
|
||||||
// 切换到配对中状态
|
|
||||||
showLoading()
|
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 显示二维码状态 */
|
/** 显示二维码状态 */
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
app:destination="@id/bindFragment"
|
app:destination="@id/bindFragment"
|
||||||
app:popUpTo="@id/nav_main" app:popUpToInclusive="true" />
|
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
|
<fragment
|
||||||
android:id="@+id/splashFragment"
|
android:id="@+id/splashFragment"
|
||||||
|
|||||||
Reference in New Issue
Block a user