diff --git a/app/build.gradle b/app/build.gradle index 235b10f6e0..fca5a86c73 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -59,9 +59,9 @@ android { // 如果不添加 `arm64` 调用系统的 PackageManager 的方法读取安装包信息的时候会出现 native 层闪退,草 // 添加了 `arm64` 以后部分 5.0 的设备会报用错 so 的问题, // couldn't find DSO to load: libimagepipeline.so caused by: dlopen failed: "/data/data/com.gh.gamecenter/lib-main/libimagepipeline.so" is 64-bit instead of 32-bit result: 0 - // 以 OPPO R7PLUS 为例,明明设备是骁龙 615,ARMv8-64 bit 的设备却不支持 arm64 的 abi + // 以 OPPO R7PLUS 为例,明明设备是骁龙 615,ARMv8-64 bit 的设备却不支持 arm64 的 abi,限制了只使用 java 后还是报错,只有 5.0,5.1 设备无法复现 : ( // 惊了 - abiFilters "armeabi-v7a", "arm64-v8a", "x86" + abiFilters "armeabi-v7a", "x86" } renderscriptTargetApi 18 @@ -310,8 +310,7 @@ dependencies { implementation "com.github.tbruyelle:rxpermissions:${rxPermissions}" - implementation "com.github.nichbar:skeleton:${skeleton}" - implementation "io.supercharge:shimmerlayout:${shimmerlayout}" + implementation "com.lg:skeleton:${skeleton}" implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:${mta}" implementation "com.github.nichbar:AndroidRomChecker:${romChecker}" @@ -325,7 +324,7 @@ dependencies { implementation "net.lingala.zip4j:zip4j:${zip4j}" - implementation "io.sentry:sentry-android:${sentry}" + implementation "io.sentry:sentry-android:4.3.0" implementation("com.github.piasy:BigImageViewer:${bigImageViewer}", { exclude group: 'com.squareup.okhttp3' diff --git a/app/src/main/java/com/gh/base/fragment/BaseLazyTabFragment.kt b/app/src/main/java/com/gh/base/fragment/BaseLazyTabFragment.kt index d77cccc19b..d3f8947b9a 100644 --- a/app/src/main/java/com/gh/base/fragment/BaseLazyTabFragment.kt +++ b/app/src/main/java/com/gh/base/fragment/BaseLazyTabFragment.kt @@ -82,7 +82,7 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL mViewPager.offscreenPageLimit = mFragmentsList.size mViewPager.addOnPageChangeListener(this) mViewPager.adapter = providePagerAdapter() - ?: FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList) + ?: FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList) mViewPager.currentItem = mCheckedIndex mTabLayout.setupWithViewPager(mViewPager) mTabIndicatorView.setupWithTabLayout(mTabLayout) @@ -105,12 +105,15 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL for (index in 0 until childCount) { val fragment = childFragmentManager.findFragmentByTag("$tag$index") if (fragment != null) { + restoreFragment(fragment) fragments.add(fragment) } } return fragments } + open fun restoreFragment(fragment: Fragment) {} + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} override fun onPageSelected(position: Int) {} diff --git a/app/src/main/java/com/gh/common/util/DownloadObserver.kt b/app/src/main/java/com/gh/common/util/DownloadObserver.kt index 6e0b3b0aea..44aae938f1 100644 --- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt +++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt @@ -8,11 +8,12 @@ import com.gh.common.exposure.ExposureUtils import com.gh.common.exposure.meta.MetaUtil import com.gh.common.simulator.SimulatorDownloadManager import com.gh.common.simulator.SimulatorGameManager -import com.gh.common.util.EnergyTaskHelper.postEnergyTask import com.gh.common.xapk.XapkInstaller import com.gh.download.DownloadDataHelper import com.gh.download.DownloadManager -import com.gh.gamecenter.* +import com.gh.gamecenter.BuildConfig +import com.gh.gamecenter.R +import com.gh.gamecenter.SuggestionActivity import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.entity.SimpleGameEntity import com.gh.gamecenter.entity.SimulatorEntity @@ -20,7 +21,7 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus import com.gh.gamecenter.eventbus.EBShowDialog import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager -import com.gh.gamecenter.setting.GameDownloadSettingFragment.Companion.AUTO_INSTALL_SP_KEY +import com.gh.gamecenter.setting.GameDownloadSettingFragment import com.gh.gamecenter.suggest.SuggestType import com.halo.assistant.HaloApp import com.lightgame.download.DataWatcher @@ -40,6 +41,9 @@ import java.util.* object DownloadObserver { private val mApplication = HaloApp.getInstance().application + // 简单 debounce 因为内存更新 downloadEntity 对象造成的触发双重下载完成事件 + // TODO 修复因为更改内存对象造成的双重下载完成事件问题,具体触发代码见 DownloadDao.updateSnapshotList + private var mDoneDebouncePair: Pair? = null // 如果在WIFI状态下,下载自动暂停,则再重试一遍 @JvmStatic @@ -114,103 +118,13 @@ object DownloadObserver { } if (DownloadStatus.done == downloadEntity.status) { - if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) { - statDoneEvent(downloadEntity) - MtaHelper.onEvent("软件更新", "下载完成") - // 会有 ActivityNotFoundException 异常,catch 掉不管了 - tryWithDefaultCatch { - if (Constants.SILENT_UPDATE != downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)) { - // TODO 在 Android 11 上没有授权安装未知应用的权限前第一次调用这个方法系统会杀掉我们的进程... - // 没能找到类似的解释,最接近的是这个 https://issuetracker.google.com/issues/154157387,但也只是点授权杀进程而已 - PackageInstaller.install(mApplication, downloadEntity); - DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据 - } - } + if (mDoneDebouncePair?.first != downloadEntity.url) { + mDoneDebouncePair = Pair(downloadEntity.url, System.currentTimeMillis()) + performDownloadCompleteAction(downloadEntity, gameId, downloadManager) } else { - statDoneEvent(downloadEntity) - - postEnergyTask("download_game", downloadEntity.gameId, downloadEntity.packageName) - val platform = PlatformUtils.getInstance(mApplication) - .getPlatformName(downloadEntity.platform) - if (platform != null) { - when { - // TODO 插件化传 path 从 apk 中获取 packageName 的形式有可能出现拿不到 packageName 的情况 - downloadEntity.isPluggable -> // 弹出插件化提示框 - EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path)) - downloadEntity.isPlugin -> Utils.toast(mApplication, downloadEntity.name + " - " + platform + " - 下载完成") - else -> Utils.toast(mApplication, downloadEntity.name + " - 下载完成") - } - } else { - Utils.toast(mApplication, downloadEntity.name + " - 下载完成") - } - if (!downloadEntity.isPluggable) { - if (downloadEntity.isSimulatorGame()) { - val simulatorJson = downloadEntity.getMetaExtra(Constants.SIMULATOR) - val gameName = downloadEntity.getMetaExtra(Constants.GAME_NAME) - if (simulatorJson.isEmpty()) return - val simulator = GsonUtils.fromJson(simulatorJson, SimulatorEntity::class.java) - val isInstalled = PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance().application, simulator.apk?.packageName) - if (!isInstalled) { - val currentActivity = AppManager.getInstance().currentActivity() - ?: return - - SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator, - SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null) - } - SimulatorGameManager.recordDownloadSimulatorGame(downloadEntity.gameId, simulator.type) - SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName) - } else { - val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) - // 是否是自动安装 - val isAutoInstall = PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean(AUTO_INSTALL_SP_KEY, true) - if (downloadType == Constants.SIMULATOR_DOWNLOAD || isAutoInstall) { - if (FileUtils.isEmptyFile(downloadEntity.path)) { - Utils.toast(mApplication, R.string.install_failure_hint) - downloadManager.cancel(downloadEntity.url) - } else { - if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) { - downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES" - tryWithDefaultCatch { - PackageInstaller.install(mApplication, downloadEntity, false) - } - } else { - // 弹出卸载提示框 - if (downloadEntity.isPlugin) { - EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path)) - } else { - EventBus.getDefault().post(EBShowDialog(BaseActivity.SIGNATURE_CONFLICT, downloadEntity.path)) - } - } - } - } - } - } - - // 统计下载完成 - uploadData(gameId, downloadEntity.platform) - } - - // 下载过程分析统计 - - // 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR - // 这里为了让它能用就不判断是否解析包错误了 - if (PackageUtils.isDeviceUnableToHandleBigApkFile(downloadEntity.path)) { - return - } - - val pm = mApplication.packageManager - val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0) - if (packageInfo == null) { - val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) - if (downloadType == Constants.SIMULATOR_DOWNLOAD) { - val currentActivity = AppManager.getInstance().currentActivity() - ?: return - DialogUtils.showSimulatorParseErrorDialog(currentActivity, downloadEntity.gameId, downloadEntity.name) { - val simulator = HaloApp.get(downloadEntity.name, true) as? SimulatorEntity - ?: return@showSimulatorParseErrorDialog - DownloadManager.getInstance(currentActivity).cancel(downloadEntity.url, true, true) - SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator, SimulatorDownloadManager.SimulatorLocation.SIMULATOR_GAME) - } + if (mDoneDebouncePair?.second == 0L + || (mDoneDebouncePair?.second ?: 0) - System.currentTimeMillis() > 500) { + performDownloadCompleteAction(downloadEntity, gameId, downloadManager) } } } @@ -235,6 +149,115 @@ object DownloadObserver { } + private fun performDownloadCompleteAction(downloadEntity: DownloadEntity, + gameId: String, + downloadManager: DownloadManager) { + if (downloadEntity.name.contains(mApplication.getString(R.string.app_name))) { + statDoneEvent(downloadEntity) + MtaHelper.onEvent("软件更新", "下载完成") + // 会有 ActivityNotFoundException 异常,catch 掉不管了 + tryWithDefaultCatch { + if (Constants.SILENT_UPDATE != downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE)) { + // TODO 在 Android 11 上没有授权安装未知应用的权限前第一次调用这个方法系统会杀掉我们的进程... + // 没能找到类似的解释,最接近的是这个 https://issuetracker.google.com/issues/154157387,但也只是点授权杀进程而已 + PackageInstaller.install(mApplication, downloadEntity); + DataLogUtils.uploadUpgradeLog(mApplication, "install") //上传更新安装数据 + } + } + } else { + statDoneEvent(downloadEntity) + + EnergyTaskHelper.postEnergyTask( + "download_game", + downloadEntity.gameId, + downloadEntity.packageName + ) + val platform = PlatformUtils.getInstance(mApplication) + .getPlatformName(downloadEntity.platform) + if (platform != null) { + when { + // TODO 插件化传 path 从 apk 中获取 packageName 的形式有可能出现拿不到 packageName 的情况 + downloadEntity.isPluggable -> // 弹出插件化提示框 + EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path)) + downloadEntity.isPlugin -> Utils.toast(mApplication, downloadEntity.name + " - " + platform + " - 下载完成") + else -> Utils.toast(mApplication, downloadEntity.name + " - 下载完成") + } + } else { + Utils.toast(mApplication, downloadEntity.name + " - 下载完成") + } + if (!downloadEntity.isPluggable) { + if (downloadEntity.isSimulatorGame()) { + val simulatorJson = downloadEntity.getMetaExtra(Constants.SIMULATOR) + val gameName = downloadEntity.getMetaExtra(Constants.GAME_NAME) + if (simulatorJson.isEmpty()) return + val simulator = GsonUtils.fromJson(simulatorJson, SimulatorEntity::class.java) + val isInstalled = PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance().application, simulator.apk?.packageName) + if (!isInstalled) { + val currentActivity = AppManager.getInstance().currentActivity() + ?: return + + SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator, + SimulatorDownloadManager.SimulatorLocation.LAUNCH, downloadEntity.gameId, gameName, null) + } + SimulatorGameManager.recordDownloadSimulatorGame(downloadEntity.gameId, simulator.type) + SimulatorGameManager.postPlayedGame(downloadEntity.gameId, downloadEntity.packageName) + } else { + val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) + // 是否是自动安装 + val isAutoInstall = PreferenceManager.getDefaultSharedPreferences(mApplication).getBoolean( + GameDownloadSettingFragment.AUTO_INSTALL_SP_KEY, true) + if (downloadType == Constants.SIMULATOR_DOWNLOAD || isAutoInstall) { + if (FileUtils.isEmptyFile(downloadEntity.path)) { + Utils.toast(mApplication, R.string.install_failure_hint) + downloadManager.cancel(downloadEntity.url) + } else { + if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) { + downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES" + tryWithDefaultCatch { + PackageInstaller.install(mApplication, downloadEntity, false) + } + } else { + // 弹出卸载提示框 + if (downloadEntity.isPlugin) { + EventBus.getDefault().post(EBShowDialog(BaseActivity.PLUGGABLE, downloadEntity.path)) + } else { + EventBus.getDefault().post(EBShowDialog(BaseActivity.SIGNATURE_CONFLICT, downloadEntity.path)) + } + } + } + } + } + } + + // 统计下载完成 + uploadData(gameId, downloadEntity.platform) + } + + // 下载过程分析统计 + + // 部分设备 (已知 vivo 5.1.1) 在调用 packageManager.getPackageArchiveInfo 获取比较大的 APK 文件时会出现 ANR + // 这里为了让它能用就不判断是否解析包错误了 + if (PackageUtils.isDeviceUnableToHandleBigApkFile(downloadEntity.path)) { + return + } + + val pm = mApplication.packageManager + val packageInfo = pm.getPackageArchiveInfo(downloadEntity.path, 0) + if (packageInfo == null) { + val downloadType = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) + if (downloadType == Constants.SIMULATOR_DOWNLOAD) { + val currentActivity = AppManager.getInstance().currentActivity() + ?: return + DialogUtils.showSimulatorParseErrorDialog(currentActivity, downloadEntity.gameId, downloadEntity.name) { + val simulator = HaloApp.get(downloadEntity.name, true) as? SimulatorEntity + ?: return@showSimulatorParseErrorDialog + DownloadManager.getInstance(currentActivity).cancel(downloadEntity.url, true, true) + SimulatorDownloadManager.getInstance().showDownloadDialog(currentActivity, simulator, SimulatorDownloadManager.SimulatorLocation.SIMULATOR_GAME) + } + } + } + } + // 统计下载完成事件 private fun statDoneEvent(downloadEntity: DownloadEntity) { var type: ExposureUtils.DownloadType diff --git a/app/src/main/java/com/gh/common/view/FixLinearLayoutManager.java b/app/src/main/java/com/gh/common/view/FixLinearLayoutManager.java index 373dec85cd..672d8fb63b 100644 --- a/app/src/main/java/com/gh/common/view/FixLinearLayoutManager.java +++ b/app/src/main/java/com/gh/common/view/FixLinearLayoutManager.java @@ -20,6 +20,13 @@ public class FixLinearLayoutManager extends LinearLayoutManager { super(context, attrs, defStyleAttr, defStyleRes); } + // 尝试避免 IndexOutOfBoundException by GapWorker + // https://stackoverflow.com/questions/43752449/recyclerview-indexoutofboundsexception-inconsistency-detected-invalid-item-pos + @Override + public boolean supportsPredictiveItemAnimations() { + return false; + } + @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { diff --git a/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt b/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt index 3867ae5b3a..de7fb70cf9 100644 --- a/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt @@ -136,7 +136,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener { mAnswerEntity = it.getParcelable(AnswerEntity::class.java.name) } - if (mUrlList?.isEmpty() == true) { + if (mUrlList == null || mUrlList?.isEmpty() == true) { ToastUtils.toast("无法查看大图") finish() } diff --git a/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragment.kt b/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragment.kt index af185923da..b1f8c742cd 100644 --- a/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragment.kt @@ -63,7 +63,7 @@ class NewInstalledGameFragment : NormalFragment() { if (locationList != null && locationList.size != 0) { var gameEntity: GameEntity? for (location in locationList) { - if (location < mInstallGameViewModel.gameListLiveData.value!!.size) { + if (location < mInstallGameViewModel.gameListLiveData.value?.size?:0) { gameEntity = mInstallGameViewModel.gameListLiveData.value?.get(location) if (gameEntity != null) { DownloadItemUtils.processDate( @@ -122,7 +122,7 @@ class NewInstalledGameFragment : NormalFragment() { }) mInstallGameViewModel.gameListLiveData.observe(this, { mSkeleton?.hide() - if (it.isNotEmpty()) { + if (!it.isNullOrEmpty()) { mAdapter?.submitList(it) } else { mBinding.fmInstallRvShow.visibility = View.GONE diff --git a/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragmentAdapter.kt index f45d8fbbfa..6a268c13b3 100644 --- a/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragmentAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/download/NewInstalledGameFragmentAdapter.kt @@ -64,8 +64,10 @@ class NewInstalledGameFragmentAdapter(context: Context, private var mViewModel: binding.root.context, gameEntity.getApk()[0].packageName ) - if (drawable.intrinsicWidth >= 300 || drawable.intrinsicHeight >= 300){ - drawable = drawable.toBitmap(200, 200).toDrawable(mContext.resources) + if (drawable != null) { + if (drawable.intrinsicWidth >= 300 || drawable.intrinsicHeight >= 300){ + drawable = drawable.toBitmap(200, 200).toDrawable(mContext.resources) + } } binding.gameIconView.getIconIv().hierarchy.setPlaceholderImage(drawable) binding.gameIconView.getIconDecoratorIv().visibility = View.GONE diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt index 308344e119..36e94ba3fe 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt @@ -11,8 +11,8 @@ import com.gh.common.constant.Constants import com.gh.common.util.* import com.gh.common.view.divider.HorizontalDividerItemDecoration import com.gh.gamecenter.R +import com.gh.gamecenter.baselist.LazyListFragment import com.gh.gamecenter.baselist.ListAdapter -import com.gh.gamecenter.baselist.ListFragment import com.gh.gamecenter.eventbus.EBDeleteDetail import com.gh.gamecenter.eventbus.EBTypeChange import com.gh.gamecenter.eventbus.EBUserFollow @@ -26,7 +26,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -class ForumArticleAskListFragment : ListFragment() { +class ForumArticleAskListFragment : LazyListFragment() { private lateinit var mAdapter: ForumArticleAskListAdapter private var mViewModel: ForumArticleAskListViewModel? = null @@ -36,7 +36,7 @@ class ForumArticleAskListFragment : ListFragment { + mAllForumArticleAskListFragment = fragment as ForumArticleAskListFragment + } + "精华" -> { + mEssenceForumArticleAskListFragment = fragment as ForumArticleAskListFragment + } + "问答" -> { + mAskForumArticleAskListFragment = fragment as ForumArticleAskListFragment + } + "视频" -> { + mVideoForumArticleAskListFragment = fragment as ForumArticleAskListFragment + } + } + } + override fun initTabTitleList(tabTitleList: MutableList) { tabTitleList.add(TAB_TITLE_ALL) tabTitleList.add(TAB_TITLE_ESSENCE) @@ -120,22 +137,6 @@ class ForumDetailFragment : BaseLazyTabFragment() { return mBinding.root } - override fun providePagerAdapter(): PagerAdapter? { - return object : FragmentStatePagerAdapter(childFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - override fun getItem(position: Int) = mFragmentsList[position] - - override fun getCount() = mFragmentsList.size - - override fun getItemPosition(`object`: Any) = PagerAdapter.POSITION_NONE - - override fun getPageTitle(position: Int): CharSequence? { - return if (mTabTitleList.size > position) { - mTabTitleList[position] - } else super.getPageTitle(position) - } - } - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) bbsId = arguments?.getString(EntranceUtils.KEY_BBS_ID, "") ?: "" diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt index 18739f6753..aaa575d086 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt @@ -3,6 +3,7 @@ package com.gh.gamecenter.forum.home import android.app.Activity import android.content.Intent import android.graphics.Typeface +import android.os.Bundle import android.view.Gravity import android.view.LayoutInflater import android.view.View @@ -13,7 +14,7 @@ import androidx.core.graphics.ColorUtils import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import com.gh.base.adapter.FragmentAdapter -import com.gh.base.fragment.LazyFragment +import com.gh.base.fragment.BaseLazyFragment import com.gh.common.dialog.TrackableDialog import com.gh.common.util.* import com.gh.gamecenter.R @@ -35,33 +36,30 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import kotlin.math.abs -class CommunityHomeFragment : LazyFragment() { +class CommunityHomeFragment : BaseLazyFragment() { private var mBinding: FragmentCommunityHomeBinding? = null private var mViewModel: CommunityHomeViewModel? = null private var mFragmentList = arrayListOf() private var mTitleList = arrayListOf("推荐", "论坛", "活动") private var mTabList = arrayListOf() + private var mDefaultSelectedTab = -1 - override fun getRealLayoutId(): Int { - return R.layout.fragment_community_home - } + override fun getLayoutId() = R.layout.fragment_community_home - override fun onRealLayoutInflated(inflatedView: View) { - mBinding = FragmentCommunityHomeBinding.bind(inflatedView) - } + override fun getInflatedLayout() = + FragmentCommunityHomeBinding.inflate(layoutInflater).apply { mBinding = this }.root override fun onFragmentFirstVisible() { mViewModel = viewModelProvider() super.onFragmentFirstVisible() + initObserver() initViewPager() } - override fun initRealView() { - super.initRealView() - + private fun initObserver() { mViewModel?.articleLiveData?.observeNonNull(viewLifecycleOwner) { insertDataToRecommendTab(it) } @@ -80,6 +78,16 @@ class CommunityHomeFragment : LazyFragment() { } } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + savedInstanceState?.let { mDefaultSelectedTab = it.getInt(LAST_SELECTED_POSITION) } + } + + override fun onSaveInstanceState(outState: Bundle) { + mBinding?.viewPager?.let { outState.putInt(LAST_SELECTED_POSITION, it.currentItem) } + super.onSaveInstanceState(outState) + } + override fun onFragmentResume() { super.onFragmentResume() @@ -92,7 +100,9 @@ class CommunityHomeFragment : LazyFragment() { } private fun initViewPager() { - val defaultSelectedPosition = arguments?.getInt(EntranceUtils.KEY_SUB_POSITION) ?: 0 + val defaultSelectedPosition = + if (mDefaultSelectedTab != -1) mDefaultSelectedTab + else arguments?.getInt(EntranceUtils.KEY_SUB_POSITION) ?: 0 mBinding?.run { mFragmentList.clear() @@ -361,5 +371,6 @@ class CommunityHomeFragment : LazyFragment() { const val ARTICLE_REQUEST_CODE = 200 const val QUESTION_REQUEST_CODE = 201 const val VIDEO_REQUEST_CODE = 202 + const val LAST_SELECTED_POSITION = "last_selected_position" } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java index ed1cb52eb4..760d9b7e14 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java @@ -167,6 +167,8 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem mGameWrapperFragment = (SearchToolWrapperFragment) fragment; } else if (fragment instanceof HomeVideoFragment) { homeVideoFragment = (HomeVideoFragment) fragment; + } else if (fragment instanceof CommunityHomeFragment) { + mCommunityHomeFragment = (CommunityHomeFragment) fragment; } } return restoreFragments; diff --git a/app/src/main/java/com/gh/gamecenter/game/rank/RankCollectionAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/rank/RankCollectionAdapter.kt index f1ca11a58d..485bebaf43 100644 --- a/app/src/main/java/com/gh/gamecenter/game/rank/RankCollectionAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/rank/RankCollectionAdapter.kt @@ -12,6 +12,7 @@ import com.gh.common.runOnUiThread import com.gh.common.util.DirectUtils import com.gh.common.util.ImageUtils import com.gh.common.util.dip2px +import com.gh.common.util.safelyGetInRelease import com.gh.common.view.AsyncCell import com.gh.gamecenter.R import com.gh.gamecenter.databinding.RankCollectionItemBinding @@ -195,7 +196,7 @@ class RankCollectionAdapter( val position = positionAndPackageMap[key] if (position != null && position < dataList.size) { dataList[position].getEntryMap()[download.platform] = download - gameItemList[position].run { + gameItemList.safelyGetInRelease(position)?.run { updateGameItem( this.rankItemUi, dataList[position], @@ -217,7 +218,7 @@ class RankCollectionAdapter( val position = positionAndPackageMap[key] if (position != null && position < dataList.size) { dataList[position].getEntryMap().remove(status.platform) - gameItemList[position].run { + gameItemList.safelyGetInRelease(position)?.run { updateGameItem( this.rankItemUi, dataList[position], @@ -239,7 +240,7 @@ class RankCollectionAdapter( mRankSubjectEntity?.data?.forEach { dataIds += it.id } for ((index, game) in mRankSubjectEntity?.data!!.withIndex()) { - gameItemList[index].run { + gameItemList.safelyGetInRelease(index)?.run { updateGameItem( this.rankItemUi, game, diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt index 0efa881e88..be0b69909e 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt @@ -33,6 +33,7 @@ import com.lightgame.utils.Utils import kotterknife.bindView import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode +import kotlin.math.abs class RatingReplyActivity : ListActivity(), KeyboardHeightObserver { @@ -44,6 +45,7 @@ class RatingReplyActivity : ListActivity(R.id.scrollView) private val mShadowView by bindView(R.id.shadowView) private val mCommentLine by bindView(R.id.comment_line) + private val mPlaceholderView by bindView(R.id.placeholderView) private var mAdapter: RatingReplyAdapter? = null @@ -58,7 +60,8 @@ class RatingReplyActivity : ListActivity map, boolean isUpload) { - AppExecutor.getLightWeightIoExecutor().execute(() -> { + AppExecutor.getLogExecutor().execute(() -> { map.put("createdOn", Utils.getTime(context)); if (isUpload) { DataCollectionManager.getInstance(context).realTimeUpload(type, map); @@ -95,7 +95,7 @@ public class DataCollectionManager { } // 添加事件 - public static void onEvent(Context context, DataCollectionInfo entity, boolean isUpload) { + private static void onEvent(Context context, DataCollectionInfo entity, boolean isUpload) { DataCollectionManager.getInstance(context).add(entity, isUpload); } @@ -159,7 +159,7 @@ public class DataCollectionManager { DataCollectionManager.getInstance(context).upsert(entity, type); } - public void upsert(DataCollectionInfo entity, String type) { + private void upsert(DataCollectionInfo entity, String type) { List list = dao.findByType(type); if (list == null || list.isEmpty()) { dao.add(entity); @@ -193,34 +193,38 @@ public class DataCollectionManager { * 统计点击数据 */ public void statClickData() { - List list = dao.getClickData(); - if (list != null && !list.isEmpty()) { - List ids = new ArrayList<>(); - List data = new ArrayList<>(); - try { - DataCollectionInfo dataCollectionEntity; - for (int i = 0, size = list.size(); i < size; i++) { - dataCollectionEntity = list.get(i); - ids.add(dataCollectionEntity.getId()); - data.add(new JSONObject(dataCollectionEntity.getData())); + AppExecutor.getLogExecutor().execute(() -> { + List list = dao.getClickData(); + if (list != null && !list.isEmpty()) { + List ids = new ArrayList<>(); + List data = new ArrayList<>(); + try { + DataCollectionInfo dataCollectionEntity; + for (int i = 0, size = list.size(); i < size; i++) { + dataCollectionEntity = list.get(i); + ids.add(dataCollectionEntity.getId()); + data.add(new JSONObject(dataCollectionEntity.getData())); + } + } catch (JSONException e) { + e.printStackTrace(); } - } catch (JSONException e) { - e.printStackTrace(); + Map map = new HashMap<>(); + map.put("data", data); + onEvent(mContext, "click", map); + dao.delete(ids); } - Map map = new HashMap<>(); - map.put("data", data); - onEvent(mContext, "click", map); - dao.delete(ids); - } + }); } public static void onEvent(Context context, String type, Map map) { - map.put("createdOn", Utils.getTime(context)); - if ("news".equals(type) || "download".equals(type) || "search".equals(type)) { - DataCollectionManager.getInstance(context).realTimeUpload(type, map); - return; - } - onEvent(context, type, new JSONObject(map).toString(), true); + AppExecutor.getLogExecutor().execute(() -> { + map.put("createdOn", Utils.getTime(context)); + if ("news".equals(type) || "download".equals(type) || "search".equals(type)) { + DataCollectionManager.getInstance(context).realTimeUpload(type, map); + return; + } + onEvent(context, type, new JSONObject(map).toString(), true); + }); } } diff --git a/app/src/main/java/com/gh/gamecenter/manager/FilterManager.java b/app/src/main/java/com/gh/gamecenter/manager/FilterManager.java index 1118af3e1d..d5227ec2a7 100644 --- a/app/src/main/java/com/gh/gamecenter/manager/FilterManager.java +++ b/app/src/main/java/com/gh/gamecenter/manager/FilterManager.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; public class FilterManager { @@ -67,7 +66,11 @@ public class FilterManager { String line; while ((line = reader.readLine()) != null) { String[] values = line.split("="); - list.add(new PackageInfo(values[0], Long.parseLong(values[1]))); + try { + list.add(new PackageInfo(values[0], Long.parseLong(values[1]))); + } catch (NumberFormatException e) { + // ignore format error + } } reader.close(); addAllFilter(list); diff --git a/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java b/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java index dd6e4fb008..31521a045a 100644 --- a/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java +++ b/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java @@ -96,6 +96,8 @@ public class MessageDetailFragment extends NormalFragment implements OnCommentCa ScrollView mScrollView; @BindView(R.id.answer_comment_content_container) View mReplyEditorContainer; + @BindView(R.id.placeholderView) + View mPlaceholderView; private LinearLayoutManager mLayoutManager; @@ -519,14 +521,18 @@ public class MessageDetailFragment extends NormalFragment implements OnCommentCa mOffset = Math.abs(height); } DisplayUtils.setLightStatusBar(requireActivity(), !isPopup); + + mPlaceholderView.setVisibility(isPopup ? View.VISIBLE : View.GONE); + LinearLayout.LayoutParams mScrollViewParams = (LinearLayout.LayoutParams) mScrollView.getLayoutParams(); mScrollViewParams.width = isPopup ? LinearLayout.LayoutParams.MATCH_PARENT : 0; - mScrollViewParams.height = isPopup ? DisplayUtils.dip2px(64f) : DisplayUtils.dip2px(28f); + mScrollViewParams.height = isPopup ? DisplayUtils.dip2px(76f) : DisplayUtils.dip2px(28f); + mScrollViewParams.topMargin = isPopup ? DisplayUtils.dip2px(8f) : 0; mScrollView.setLayoutParams(mScrollViewParams); RelativeLayout.LayoutParams mLayoutParams = (RelativeLayout.LayoutParams) mReplyEditorContainer.getLayoutParams(); - mLayoutParams.height = isPopup ? DisplayUtils.dip2px(130f) : LinearLayout.LayoutParams.WRAP_CONTENT; - mLayoutParams.bottomMargin = isPopup ? height + mOffset - DisplayUtils.dip2px(12f) : 0; + mLayoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT; + mLayoutParams.bottomMargin = isPopup ? height + mOffset : 0; mReplyEditorContainer.setLayoutParams(mLayoutParams); } diff --git a/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java b/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java index 948994a277..3045b5b42d 100644 --- a/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java +++ b/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java @@ -711,19 +711,10 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder context.startActivity(GameCollectionDetailActivity.getIntent(context, entity.getGameList().getId(), false, true)); break; case "game_list_comment_reply": - context.startActivity(CommentActivity.getGameCollectionCommentDetailIntent( - context, - entity.getComment().getTopId(), - entity.getGameList().getId(), - false, - entrance, - path - )); - break; case "game_list_comment_vote": context.startActivity(CommentActivity.getGameCollectionCommentDetailIntent( context, - entity.getComment().getId(), + entity.getComment().getTopId(), entity.getGameList().getId(), false, entrance, diff --git a/app/src/main/java/com/halo/assistant/HaloApp.java b/app/src/main/java/com/halo/assistant/HaloApp.java index c411bff51f..cb107e96a3 100644 --- a/app/src/main/java/com/halo/assistant/HaloApp.java +++ b/app/src/main/java/com/halo/assistant/HaloApp.java @@ -359,18 +359,21 @@ public class HaloApp extends MultiDexApplication { // 会出现找不到 arm64 so 的情况,具体可见 // https://sentry.ghzs.com/organizations/lightgame/issues/53107/ // 所以这里尝试在 5.0 & 5.1 设备上关闭 fresco 的 native 解码,应该会让 5.0 & 5.1 的设备 OOM 概率提高,但先试试效果 - ImagePipelineConfig.Builder configBuilder = ImagePipelineConfig.newBuilder(this); + // 效果不好,还是有闪退,麻了,见 https://sentry.ghzs.com/organizations/lightgame/issues/86665/ + // 难道非得换成不用 SO 的 Glide ? - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP - || Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1) { - configBuilder.setMemoryChunkType(MemoryChunkType.BUFFER_MEMORY) - .setImageTranscoderType(ImageTranscoderType.JAVA_TRANSCODER) - .experiment() - .setNativeCodeDisabled(true); - } +// ImagePipelineConfig.Builder configBuilder = ImagePipelineConfig.newBuilder(this); + +// if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP +// || Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1) { +// configBuilder.setMemoryChunkType(MemoryChunkType.BUFFER_MEMORY) +// .setImageTranscoderType(ImageTranscoderType.JAVA_TRANSCODER) +// .experiment() +// .setNativeCodeDisabled(true); +// } try { - BigImageViewer.initialize(FrescoImageLoader.with(this, configBuilder.build())); + BigImageViewer.initialize(FrescoImageLoader.with(this)); } catch (Throwable e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameFragment.kt b/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameFragment.kt index caf616587c..8447029c93 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameFragment.kt +++ b/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameFragment.kt @@ -1,5 +1,6 @@ package com.halo.assistant.fragment.user +import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri import android.os.Bundle @@ -130,8 +131,22 @@ class ManuallyRealNameFragment : NormalFragment() { } private fun selectImage() { - val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) - startActivityForResult(intent, REQUEST_IMAGE) + try { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + startActivityForResult(intent, REQUEST_IMAGE) + } catch (e: ActivityNotFoundException) { + // https://stackoverflow.com/questions/45707678 + val getIntent = Intent(Intent.ACTION_GET_CONTENT) + getIntent.type = "image/*" + + val pickIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + pickIntent.type = "image/*" + + val chooserIntent = Intent.createChooser(getIntent, "Select Image") + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(pickIntent)) + + startActivityForResult(chooserIntent, REQUEST_IMAGE) + } } private fun removeUploadedImage() { diff --git a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt index 2bb8613095..01814b574a 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt +++ b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt @@ -268,7 +268,7 @@ class RealNameInfoFragment : NormalFragment() { * 屏幕高度小于等于 1080 (16:9) 的设备看作无法显示完整内容 */ private fun isScreenUnableToShowAllTheContent(): Boolean { - return DisplayUtils.getScreenHeight() <= 1080 + return DisplayUtils.getScreenHeight() <= 1920 } private fun changeToCompatView() { @@ -346,7 +346,7 @@ class RealNameInfoFragment : NormalFragment() { ConstraintSet.TOP, R.id.idCardEt, ConstraintSet.BOTTOM, - 4F.dip2px() + 24F.dip2px() ) }.applyTo(mBinding.infoContainer) } diff --git a/dependencies.gradle b/dependencies.gradle index a8d83c64cc..5ae170f5a0 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,8 +7,8 @@ ext { targetSdkVersion = 26 // application info (每个大版本之间的 versionCode 增加 20) - versionCode = 450 - versionName = "5.5.0" + versionCode = 453 + versionName = "5.5.3" applicationId = "com.gh.gamecenter" // AndroidX @@ -97,8 +97,7 @@ ext { flexbox = "1.1.0" pickerView = "4.1.8" verifier = "1.0.6" - skeleton = "1.1.3" - shimmerlayout = "2.1.0" + skeleton = "1.1.4" mta = "6.7.9" romChecker = "1.0.3" oss = "2.9.2"