From 96734e3ead57b14c6429e109fcb2c5fbcaee0d72 Mon Sep 17 00:00:00 2001 From: chenjuntao Date: Fri, 24 Nov 2023 17:22:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E6=B8=B8=E6=88=8F=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E9=97=AA=E9=80=80=E9=97=AE=E9=A2=98=20https://sentry.shanqu.cc?= =?UTF-8?q?/organizations/lightgame/issues/352562?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GameSubstituteRepositoryProviderImpl.kt | 4 +- .../java/com/gh/common/util/DataUtils.java | 2 +- .../util/GameSubstituteRepositoryHelper.kt | 103 +++++++++--------- .../com/gh/gamecenter/game/GameViewModel.kt | 5 +- .../com/gh/gamecenter/home/HomeViewModel.kt | 10 +- .../com/gh/gamecenter/qgame/QGameViewModel.kt | 2 +- .../IGameSubstituteRepositoryProvider.kt | 2 +- .../gamecenter/login/user/UserRepository.java | 4 +- 8 files changed, 62 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/com/gh/common/provider/GameSubstituteRepositoryProviderImpl.kt b/app/src/main/java/com/gh/common/provider/GameSubstituteRepositoryProviderImpl.kt index df02a5cc78..730d4638f8 100644 --- a/app/src/main/java/com/gh/common/provider/GameSubstituteRepositoryProviderImpl.kt +++ b/app/src/main/java/com/gh/common/provider/GameSubstituteRepositoryProviderImpl.kt @@ -9,8 +9,8 @@ import com.gh.gamecenter.core.provider.IGameSubstituteRepositoryProvider @Route(path = RouteConsts.provider.gameSubstituteRepository, name = "GameSubstituteRepositoryHelper暴露服务") class GameSubstituteRepositoryProviderImpl : IGameSubstituteRepositoryProvider { - override fun updateSubstitutableGames() { - GameSubstituteRepositoryHelper.updateSubstitutableGames() + override fun updateHistoricInstalledGameSet() { + GameSubstituteRepositoryHelper.updateHistoricInstalledGameSet() } override fun init(context: Context?) { diff --git a/app/src/main/java/com/gh/common/util/DataUtils.java b/app/src/main/java/com/gh/common/util/DataUtils.java index 78f85e4de1..9a92220453 100644 --- a/app/src/main/java/com/gh/common/util/DataUtils.java +++ b/app/src/main/java/com/gh/common/util/DataUtils.java @@ -132,7 +132,7 @@ public class DataUtils { // 避免重复调用 if (!TextUtils.isEmpty(gid)) { - GameSubstituteRepositoryHelper.updateSubstitutableGames(); + GameSubstituteRepositoryHelper.updateHistoricInstalledGameSet(); } getDeviceCertification(gid); diff --git a/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt b/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt index 4231600827..4ae5ef8c4c 100644 --- a/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt +++ b/app/src/main/java/com/gh/common/util/GameSubstituteRepositoryHelper.kt @@ -1,12 +1,12 @@ package com.gh.common.util import android.annotation.SuppressLint +import android.content.Context import android.text.TextUtils import com.gh.gamecenter.core.utils.SPUtils import com.gh.gamecenter.common.utils.doOnMainProcessOnly import com.gh.gamecenter.common.utils.toJson import com.gh.gamecenter.common.utils.toObject -import com.gh.gamecenter.core.utils.MtaHelper import com.gh.gamecenter.feature.entity.GameEntity import com.gh.gamecenter.entity.SubjectEntity import com.gh.gamecenter.login.user.UserManager @@ -18,17 +18,19 @@ import com.lightgame.utils.Utils import io.reactivex.schedulers.Schedulers /** - * 首页补充游戏库辅助类 + * 补充游戏库管理类 */ object GameSubstituteRepositoryHelper { + private const val SP_GAME_SUB = "sp_game_sub" private const val KEY_GAME_REPOSITORY = "game_substitute_repository" - private var mSubstitutableGameIdSet = hashSetOf() private var mApi = RetrofitManager.getInstance().api + private var mHistoricInstalledGameIdSet = hashSetOf() // 历史已安装过的游戏 ID 列表 private var mApplicationContext = HaloApp.getInstance().application + private val mGameSubSp by lazy { mApplicationContext.getSharedPreferences(SP_GAME_SUB, Context.MODE_PRIVATE) } - var gameCollectionList: List = arrayListOf() + private var mGameCollectionList: List = arrayListOf() // 游戏补充库 init { loadSavedRepository() @@ -50,9 +52,13 @@ object GameSubstituteRepositoryHelper { }) } + /** + * 联网获取历史已安装过的游戏 ID 列表 + * 包括根据用户 ID 获取的已玩游戏 ID 列表,以及根据 gid 获取的已下载游戏 ID 列表 + */ @JvmStatic @SuppressLint("CheckResult") - fun updateSubstitutableGames() { + fun updateHistoricInstalledGameSet() { mApplicationContext.doOnMainProcessOnly { val single = if (UserManager.getInstance().isLoggedIn) { mApi.getIdListOfPlayedGames(UserManager.getInstance().userId, Utils.getTime(mApplicationContext)) @@ -61,28 +67,22 @@ object GameSubstituteRepositoryHelper { } single.subscribeOn(Schedulers.io()).subscribe(object : BiResponse>() { override fun onSuccess(data: List) { - mSubstitutableGameIdSet = data.toHashSet() + mHistoricInstalledGameIdSet = data.toHashSet() } }) } } - /** - * 刷新内存中的游戏库(即从 SP 中再读一次) - */ - @JvmStatic - fun refreshRepositoryFromLocal() = loadSavedRepository() - private fun loadSavedRepository() { - gameCollectionList = SPUtils.getString(KEY_GAME_REPOSITORY).toObject() ?: arrayListOf() + mGameCollectionList = SPUtils.getString(mGameSubSp, KEY_GAME_REPOSITORY).toObject() ?: arrayListOf() } private fun updateGameRepository(subjects: List?) { if (subjects == null) return - SPUtils.setString(KEY_GAME_REPOSITORY, subjects.toJson()) + SPUtils.setString(mGameSubSp, KEY_GAME_REPOSITORY, subjects.toJson()) - gameCollectionList = subjects + mGameCollectionList = subjects } /** @@ -90,19 +90,12 @@ object GameSubstituteRepositoryHelper { * @param collectionId 补充游戏库相应专题 ID * @param gameIdList 该专题里已经包含的游戏 ID 列表 */ - private fun getOneUniqueGame(collectionId: String?, gameIdList: HashSet): GameEntity? { + private fun getValidGame(collectionId: String?, gameIdList: HashSet): GameEntity? { collectionId?.let { - val collection = gameCollectionList.find { it.id == collectionId } + val collection = mGameCollectionList.find { it.id == collectionId } collection?.let { - val game = collection.data?.find { game -> isThisGameUnique(game, gameIdList) } + val game = collection.data?.find { game -> isThisGameValid(game, gameIdList) } game?.let { - collection.data?.remove(game) -// collection.data?.size?.let { remainingSize -> -// // 记录被替换游戏的数量,10个以上的时候触发 -// if (remainingSize % 10 == 0) { -// SentryHelper.onEvent("game_substitute", "substituted_size", "${50 - remainingSize}") -// } -// } // 产品说要记录补充专题的曝光数,所以这个游戏附带了所在专题的名字 game.subjectName = collection.name game.subjectId = collection.id @@ -115,14 +108,17 @@ object GameSubstituteRepositoryHelper { /** * 替换游戏,包括 已安装,历史下载,历史已安装等类型 + * @param gameList 需要被替换数据的游戏列表 + * @param displayingGameIdSet 页面正在显示的游戏 ID 列表,避免重复替换 + * @param relatedCollectionId 关联的替换合集 ID */ fun replaceGames( gameList: MutableList, - alreadyDisplayedGameIdSet: HashSet, + displayingGameIdSet: HashSet, relatedCollectionId: String, - shouldLogReplaceEvent: Boolean ) { - val positionOfTheGameToReplaceList = arrayListOf() + // 需要被替换的游戏 position 列表 + val positionOfGameToBeReplacedList = arrayListOf() // 标记需要替换的已安装游戏 for ((index, game) in gameList.withIndex()) { @@ -132,28 +128,29 @@ object GameSubstituteRepositoryHelper { continue } - var isThisPositionLabeled = false + // 这个 position 的游戏是否需要被替换 + var thisPositionNeedToBeReplaced = false // 从 游戏ID 判断当前游戏是否需要被替换 - if (mSubstitutableGameIdSet.contains(game.id)) { - positionOfTheGameToReplaceList.add(index) - isThisPositionLabeled = true + if (mHistoricInstalledGameIdSet.contains(game.id)) { + positionOfGameToBeReplacedList.add(index) + thisPositionNeedToBeReplaced = true } // 检查是否已安装该游戏里同包名的 APK - if (!isThisPositionLabeled) { + if (!thisPositionNeedToBeReplaced) { for (apk in game.getApk()) { if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) { // 将该位置的游戏标记为需要替换 - positionOfTheGameToReplaceList.add(index) - isThisPositionLabeled = true + positionOfGameToBeReplacedList.add(index) + thisPositionNeedToBeReplaced = true break } } } // 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名 - if (!isThisPositionLabeled) { + if (!thisPositionNeedToBeReplaced) { var relatedPackageList = arrayListOf() for (entity in PackageHelper.relatedPackageList) { if (entity.gameId == game.id) { @@ -164,39 +161,45 @@ object GameSubstituteRepositoryHelper { for (packageName in relatedPackageList) { if (PackageHelper.validLocalPackageNameSet.contains(packageName)) { - positionOfTheGameToReplaceList.add(index) + positionOfGameToBeReplacedList.add(index) break } } } } - if (positionOfTheGameToReplaceList.isNotEmpty()) { - if (shouldLogReplaceEvent) { - MtaHelper.onEvent("首页_加载", "启动光环", "替换游戏") - } - for (position in positionOfTheGameToReplaceList) { - val replacingGame = getOneUniqueGame(relatedCollectionId, alreadyDisplayedGameIdSet) - replacingGame?.let { - gameList[position] = replacingGame + if (positionOfGameToBeReplacedList.isNotEmpty()) { + for (position in positionOfGameToBeReplacedList) { + val validGame = getValidGame(relatedCollectionId, displayingGameIdSet) + validGame?.let { + gameList[position] = it + displayingGameIdSet.add(it.id) } } } } - private fun isThisGameUnique(game: GameEntity, gameIdList: HashSet): Boolean { - // 判断该游戏是否出现在已安装列表 - if (mSubstitutableGameIdSet.contains(game.id)) return false + /** + * 判断该游戏是否有效 + * @param game 需要判断的游戏 + * @param gameIdList 专题里已经包含的游戏 ID 列表 + */ + private fun isThisGameValid( + game: GameEntity, + gameIdList: HashSet + ): Boolean { + // 该游戏是否在历史已安装列表中 + if (mHistoricInstalledGameIdSet.contains(game.id)) return false - // 该补充游戏是否已经存在关联关系 + // 该游戏是否与专题里已包含的游戏存在关联关系 for (relatedId in game.relatedGameIds!!) { if (gameIdList.contains(relatedId)) { return false } } + // 检查本地是否已安装该游戏,已过滤部分框架服务的包名 for (apk in game.getApk()) { - // 检查本地是否已安装该游戏,已过滤那部分框架服务的包名 if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) { return false } diff --git a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt index d8505c916c..6ed6db1b5a 100644 --- a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt @@ -115,9 +115,6 @@ class GameViewModel(application: Application, override var blockData: SubjectRec ) { getSmartColumn() } - - // 触发列表刷新行为时亦刷新内存中的备用游戏库列表 - GameSubstituteRepositoryHelper.refreshRepositoryFromLocal() } fun showRecentVGame() = mIsFromHome && blockData?.text?.contains("畅玩广场") == true @@ -732,7 +729,7 @@ class GameViewModel(application: Application, override var blockData: SubjectRec if (!data.isNullOrEmpty()) { subjectEntity.relatedColumnId?.let { - GameSubstituteRepositoryHelper.replaceGames(data, mSubjectGameIdList, it, false) + GameSubstituteRepositoryHelper.replaceGames(data, mSubjectGameIdList, it) } } val shouldShowDivider = subjectEntity.type == "game" || subjectEntity.type == "video" diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt index 1da3ca4897..563f55f5ad 100644 --- a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt @@ -125,9 +125,6 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { loadStatus.postValue(LoadStatus.INIT_LOADED) } - // 触发列表刷新行为时亦刷新内存中的备用游戏库列表 - GameSubstituteRepositoryHelper.refreshRepositoryFromLocal() - if (SPUtils.getBoolean(Constants.SP_PERSONAL_RECOMMEND, true)) { getSmartColumn() } @@ -744,12 +741,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { } subjectEntity.relatedColumnId?.let { - GameSubstituteRepositoryHelper.replaceGames( - data, - mSubjectGameIdList, - it, - mShouldLogReplaceEvent - ) + GameSubstituteRepositoryHelper.replaceGames(data, mSubjectGameIdList, it) mShouldLogReplaceEvent = false } } diff --git a/app/src/main/java/com/gh/gamecenter/qgame/QGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/qgame/QGameViewModel.kt index 49c1dfdb07..55bd9bb81e 100644 --- a/app/src/main/java/com/gh/gamecenter/qgame/QGameViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qgame/QGameViewModel.kt @@ -193,7 +193,7 @@ class QGameViewModel(application: Application, blockData: SubjectRecommendEntity if (!data.isNullOrEmpty()) { subjectEntity.relatedColumnId?.let { - GameSubstituteRepositoryHelper.replaceGames(data, mSubjectGameIdList, it, false) + GameSubstituteRepositoryHelper.replaceGames(data, mSubjectGameIdList, it) } } val shouldShowDivider = subjectEntity.type == "game" || subjectEntity.type == "video" diff --git a/module_core/src/main/java/com/gh/gamecenter/core/provider/IGameSubstituteRepositoryProvider.kt b/module_core/src/main/java/com/gh/gamecenter/core/provider/IGameSubstituteRepositoryProvider.kt index 9b56e63df5..d3badb765f 100644 --- a/module_core/src/main/java/com/gh/gamecenter/core/provider/IGameSubstituteRepositoryProvider.kt +++ b/module_core/src/main/java/com/gh/gamecenter/core/provider/IGameSubstituteRepositoryProvider.kt @@ -4,6 +4,6 @@ import com.alibaba.android.arouter.facade.template.IProvider interface IGameSubstituteRepositoryProvider : IProvider { - fun updateSubstitutableGames() + fun updateHistoricInstalledGameSet() } \ No newline at end of file diff --git a/module_login/src/main/java/com/gh/gamecenter/login/user/UserRepository.java b/module_login/src/main/java/com/gh/gamecenter/login/user/UserRepository.java index a797240557..07b3b97d23 100644 --- a/module_login/src/main/java/com/gh/gamecenter/login/user/UserRepository.java +++ b/module_login/src/main/java/com/gh/gamecenter/login/user/UserRepository.java @@ -151,7 +151,7 @@ public class UserRepository { IGameSubstituteRepositoryProvider gameSubstituteRepository = (IGameSubstituteRepositoryProvider) ARouter.getInstance().build(RouteConsts.provider.gameSubstituteRepository).navigation(); if (gameSubstituteRepository != null) { - gameSubstituteRepository.updateSubstitutableGames(); + gameSubstituteRepository.updateHistoricInstalledGameSet(); } // 通知页面更新 @@ -245,7 +245,7 @@ public class UserRepository { IGameSubstituteRepositoryProvider gameSubstituteRepository = (IGameSubstituteRepositoryProvider) ARouter.getInstance().build(RouteConsts.provider.gameSubstituteRepository).navigation(); if (gameSubstituteRepository != null) { - gameSubstituteRepository.updateSubstitutableGames(); + gameSubstituteRepository.updateHistoricInstalledGameSet(); } IWechatBindHelperProvider wechatBindHelper = (IWechatBindHelperProvider) ARouter.getInstance().build(RouteConsts.provider.wechatHelper).navigation(); if (wechatBindHelper != null) {