From 757444c6b45a6d90fa68aaa347bfcd1b7e8aea0b Mon Sep 17 00:00:00 2001 From: ShirosakiMio <852468399@qq.com> Date: Mon, 9 Sep 2024 10:33:58 +0800 Subject: [PATCH] Optimize app startup speed --- FCL/src/main/java/com/mio/util/AnimUtil.kt | 6 + FCL/src/main/java/com/mio/util/PerfUtil.kt | 61 +++++++ .../java/com/tungsten/fcl/FCLApplication.java | 3 + .../com/tungsten/fcl/activity/MainActivity.kt | 86 ++++++--- .../tungsten/fcl/activity/SplashActivity.java | 13 +- .../tungsten/fcl/fragment/RuntimeFragment.kt | 13 +- .../com/tungsten/fcl/setting/Settings.java | 3 +- .../java/com/tungsten/fcl/ui/UIManager.java | 169 ------------------ .../java/com/tungsten/fcl/ui/UIManager.kt | 98 ++++++++++ .../com/tungsten/fcl/ui/manage/ManageUI.java | 3 + 10 files changed, 239 insertions(+), 216 deletions(-) create mode 100644 FCL/src/main/java/com/mio/util/PerfUtil.kt delete mode 100644 FCL/src/main/java/com/tungsten/fcl/ui/UIManager.java create mode 100644 FCL/src/main/java/com/tungsten/fcl/ui/UIManager.kt diff --git a/FCL/src/main/java/com/mio/util/AnimUtil.kt b/FCL/src/main/java/com/mio/util/AnimUtil.kt index 776467d9..e2f67183 100644 --- a/FCL/src/main/java/com/mio/util/AnimUtil.kt +++ b/FCL/src/main/java/com/mio/util/AnimUtil.kt @@ -95,5 +95,11 @@ class AnimUtil { this.interpolator = interpolator return this } + + @JvmStatic + fun ObjectAnimator.startAfter(delayTime: Long) { + this.startDelay = delayTime + this.start() + } } } \ No newline at end of file diff --git a/FCL/src/main/java/com/mio/util/PerfUtil.kt b/FCL/src/main/java/com/mio/util/PerfUtil.kt new file mode 100644 index 00000000..f52b3db9 --- /dev/null +++ b/FCL/src/main/java/com/mio/util/PerfUtil.kt @@ -0,0 +1,61 @@ +package com.mio.util + +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import android.util.Log +import android.util.Printer + +class PerfUtil : Printer { + companion object { + @JvmStatic + fun install() { + Looper.getMainLooper().setMessageLogging(PerfUtil()) + } + } + + private val sampler = StackSampler(300) + private var isStarted = false + private var startTime = 0L + + override fun println(x: String?) { + if (!isStarted) { + isStarted = true + startTime = System.currentTimeMillis() + sampler.startDump() + } else { + isStarted = false + val endTime = System.currentTimeMillis() + if (endTime - startTime > 300) { + Log.e("FCL PerfUtil", "block time = ${endTime - startTime}") + } + sampler.stopDump() + } + } + + inner class StackSampler(val interval: Long) { + private val handler: Handler + private val runnable = Runnable { + val sb = StringBuilder() + Looper.getMainLooper().thread.stackTrace.forEach { + sb.append(it.toString()) + sb.append("\n") + } + Log.e("FCL PerfUtil", sb.toString()) + } + + init { + val handlerThread = HandlerThread("") + handlerThread.start() + handler = Handler(handlerThread.looper) + } + + fun startDump() { + handler.postDelayed(runnable, interval) + } + + fun stopDump() { + handler.removeCallbacks(runnable) + } + } +} \ No newline at end of file diff --git a/FCL/src/main/java/com/tungsten/fcl/FCLApplication.java b/FCL/src/main/java/com/tungsten/fcl/FCLApplication.java index 1af54552..77c14253 100644 --- a/FCL/src/main/java/com/tungsten/fcl/FCLApplication.java +++ b/FCL/src/main/java/com/tungsten/fcl/FCLApplication.java @@ -8,6 +8,8 @@ import android.os.StrictMode; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.mio.util.PerfUtil; + import java.lang.ref.WeakReference; public class FCLApplication extends Application implements Application.ActivityLifecycleCallbacks { @@ -18,6 +20,7 @@ public class FCLApplication extends Application implements Application.ActivityL // enabledStrictMode(); super.onCreate(); this.registerActivityLifecycleCallbacks(this); + PerfUtil.install(); } public static Activity getCurrentActivity() { diff --git a/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.kt b/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.kt index 6a5e5fed..7d039072 100644 --- a/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.kt +++ b/FCL/src/main/java/com/tungsten/fcl/activity/MainActivity.kt @@ -9,10 +9,14 @@ import android.os.Bundle import android.view.KeyEvent import android.view.View import android.view.ViewGroup +import android.view.animation.BounceInterpolator import android.widget.RelativeLayout import androidx.appcompat.app.AlertDialog import androidx.core.view.forEach import androidx.databinding.DataBindingUtil +import com.mio.util.AnimUtil +import com.mio.util.AnimUtil.Companion.interpolator +import com.mio.util.AnimUtil.Companion.startAfter import com.tungsten.fcl.R import com.tungsten.fcl.databinding.ActivityMainBinding import com.tungsten.fcl.game.JarExecutorHelper @@ -246,6 +250,11 @@ class MainActivity : FCLActivity(), OnSelectListener, View.OnClickListener { _uiManager?.onResume() } + override fun onStart() { + super.onStart() + playAnim() + } + override fun onSelect(view: FCLMenuView) { refreshMenuView(view) bind.apply { @@ -394,41 +403,45 @@ class MainActivity : FCLActivity(), OnSelectListener, View.OnClickListener { version ) ) { - val game = Profiles.getSelectedProfile().repository.getGameVersion(version) - .orElse(getString(R.string.message_unknown)) - val libraries = StringBuilder(game) - val analyzer = LibraryAnalyzer.analyze( - Profiles.getSelectedProfile().repository.getResolvedPreservingPatchesVersion(version) - ) - for (mark in analyzer) { - val libraryId = mark.libraryId - val libraryVersion = mark.libraryVersion - if (libraryId == LibraryType.MINECRAFT.patchId) continue - if (AndroidUtils.hasStringId( - this, - "install_installer_" + libraryId.replace("-", "_") - ) - ) { - libraries.append(", ").append( - AndroidUtils.getLocalizedText( + Schedulers.defaultScheduler().execute { + val game = Profiles.getSelectedProfile().repository.getGameVersion(version) + .orElse(getString(R.string.message_unknown)) + val libraries = StringBuilder(game) + val analyzer = LibraryAnalyzer.analyze( + Profiles.getSelectedProfile().repository.getResolvedPreservingPatchesVersion(version) + ) + for (mark in analyzer) { + val libraryId = mark.libraryId + val libraryVersion = mark.libraryVersion + if (libraryId == LibraryType.MINECRAFT.patchId) continue + if (AndroidUtils.hasStringId( this, "install_installer_" + libraryId.replace("-", "_") ) - ) - if (libraryVersion != null) libraries.append(": ").append( - libraryVersion.replace( - "(?i)$libraryId".toRegex(), "" + ) { + libraries.append(", ").append( + AndroidUtils.getLocalizedText( + this, + "install_installer_" + libraryId.replace("-", "_") + ) + ) + if (libraryVersion != null) libraries.append(": ").append( + libraryVersion.replace( + "(?i)$libraryId".toRegex(), "" + ) + ) + } + } + Schedulers.androidUIThread().execute { + bind.versionName.text = version + bind.versionHint.text = libraries.toString() + bind.icon.setBackgroundDrawable( + Profiles.getSelectedProfile().repository.getVersionIconImage( + version ) ) } } - bind.versionName.text = version - bind.versionHint.text = libraries.toString() - bind.icon.setBackgroundDrawable( - Profiles.getSelectedProfile().repository.getVersionIconImage( - version - ) - ) } else { bind.versionName.text = getString(R.string.version_no_version) bind.versionHint.text = getString(R.string.version_manage) @@ -454,4 +467,21 @@ class MainActivity : FCLActivity(), OnSelectListener, View.OnClickListener { }) } } + + private fun playAnim() { + bind.apply { + AnimUtil.playTranslationX( + leftMenu, + ThemeEngine.getInstance().getTheme().animationSpeed * 30L, + -100f, + 0f + ).interpolator(BounceInterpolator()).start() + AnimUtil.playTranslationX( + rightMenu, + ThemeEngine.getInstance().getTheme().animationSpeed * 30L, + 100f, + 0f + ).interpolator(BounceInterpolator()).start() + } + } } \ No newline at end of file diff --git a/FCL/src/main/java/com/tungsten/fcl/activity/SplashActivity.java b/FCL/src/main/java/com/tungsten/fcl/activity/SplashActivity.java index 1769d524..f060be31 100644 --- a/FCL/src/main/java/com/tungsten/fcl/activity/SplashActivity.java +++ b/FCL/src/main/java/com/tungsten/fcl/activity/SplashActivity.java @@ -41,9 +41,6 @@ public class SplashActivity extends FCLActivity { public ConstraintLayout background; - private EulaFragment eulaFragment; - private RuntimeFragment runtimeFragment; - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -103,21 +100,15 @@ public class SplashActivity extends FCLActivity { FCLPath.loadPaths(this); transFile(); Logging.start(Paths.get(FCLPath.LOG_DIR)); - initFragments(); start(); } - private void initFragments() { - eulaFragment = new EulaFragment(); - runtimeFragment = new RuntimeFragment(); - } - public void start() { SharedPreferences sharedPreferences = getSharedPreferences("launcher", MODE_PRIVATE); if (sharedPreferences.getBoolean("isFirstLaunch", true)) { - getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.frag_start_anim, R.anim.frag_stop_anim).replace(R.id.fragment, eulaFragment).commit(); + getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.frag_start_anim, R.anim.frag_stop_anim).replace(R.id.fragment, EulaFragment.class, null).commit(); } else { - getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.frag_start_anim, R.anim.frag_stop_anim).replace(R.id.fragment, runtimeFragment).commit(); + getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.frag_start_anim, R.anim.frag_stop_anim).replace(R.id.fragment, RuntimeFragment.class, null).commit(); } } diff --git a/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.kt b/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.kt index 672931b8..f64f4a5c 100644 --- a/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.kt +++ b/FCL/src/main/java/com/tungsten/fcl/fragment/RuntimeFragment.kt @@ -1,6 +1,5 @@ package com.tungsten.fcl.fragment -import android.annotation.SuppressLint import android.graphics.Color import android.os.Bundle import android.view.LayoutInflater @@ -12,11 +11,9 @@ import com.tungsten.fcl.activity.SplashActivity import com.tungsten.fcl.databinding.FragmentRuntimeBinding import com.tungsten.fcl.util.RuntimeUtils import com.tungsten.fclauncher.utils.FCLPath +import com.tungsten.fclcore.task.Schedulers import com.tungsten.fclcore.util.io.FileUtils import com.tungsten.fcllibrary.component.FCLFragment -import com.tungsten.fcllibrary.component.view.FCLButton -import com.tungsten.fcllibrary.component.view.FCLImageView -import com.tungsten.fcllibrary.component.view.FCLProgressBar import com.tungsten.fcllibrary.util.LocaleUtils import java.io.File import java.io.IOException @@ -41,10 +38,12 @@ class RuntimeFragment : FCLFragment(), View.OnClickListener { ): View? { val view = inflater.inflate(R.layout.fragment_runtime, container, false) bind = FragmentRuntimeBinding.bind(view) - initState() - refreshDrawables() - check() bind.install.setOnClickListener(this) + Schedulers.defaultScheduler().execute { + initState() + refreshDrawables() + check() + } return view } diff --git a/FCL/src/main/java/com/tungsten/fcl/setting/Settings.java b/FCL/src/main/java/com/tungsten/fcl/setting/Settings.java index c65f60f3..3f24944e 100644 --- a/FCL/src/main/java/com/tungsten/fcl/setting/Settings.java +++ b/FCL/src/main/java/com/tungsten/fcl/setting/Settings.java @@ -19,6 +19,7 @@ package com.tungsten.fcl.setting; import com.tungsten.fcl.game.FCLCacheRepository; import com.tungsten.fclauncher.utils.FCLPath; +import com.tungsten.fclcore.task.Schedulers; import com.tungsten.fclcore.util.CacheRepository; public final class Settings { @@ -43,7 +44,7 @@ public final class Settings { DownloadProviders.init(); Accounts.init(); Profiles.init(); - Controllers.init(); + Schedulers.defaultScheduler().execute(Controllers::init); AuthlibInjectorServers.init(); CacheRepository.setInstance(FCLCacheRepository.REPOSITORY); diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.java b/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.java deleted file mode 100644 index f4947eb9..00000000 --- a/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.tungsten.fcl.ui; - -import android.content.Context; - -import com.tungsten.fcl.R; -import com.tungsten.fcl.ui.account.AccountUI; -import com.tungsten.fcl.ui.controller.ControllerUI; -import com.tungsten.fcl.ui.download.DownloadUI; -import com.tungsten.fcl.ui.manage.ManageUI; -import com.tungsten.fcl.ui.main.MainUI; -import com.tungsten.fcl.ui.multiplayer.MultiplayerUI; -import com.tungsten.fcl.ui.setting.SettingUI; -import com.tungsten.fcl.ui.version.VersionUI; -import com.tungsten.fclcore.util.Logging; -import com.tungsten.fcllibrary.component.ui.FCLBaseUI; -import com.tungsten.fcllibrary.component.ui.FCLCommonUI; -import com.tungsten.fcllibrary.component.view.FCLUILayout; - -import java.util.logging.Level; - -public class UIManager { - - private static UIManager instance; - - public static UIManager getInstance() { - if (instance == null) { - throw new IllegalStateException("UIManager not initialized!"); - } - return instance; - } - - private final Context context; - private final FCLUILayout parent; - - private MainUI mainUI; - private AccountUI accountUI; - private VersionUI versionUI; - private ManageUI manageUI; - private DownloadUI downloadUI; - private ControllerUI controllerUI; - private MultiplayerUI multiplayerUI; - private SettingUI settingUI; - - private FCLBaseUI[] allUIs; - private FCLBaseUI currentUI; - - private int loadedUI = 0; - - public UIManager(Context context, FCLUILayout parent) { - this.context = context; - this.parent = parent; - } - - public void init(UIListener listener) { - if (instance != null) { - Logging.LOG.log(Level.WARNING, "UIManager already initialized!"); - return; - } - instance = this; - - mainUI = new MainUI(context, parent, R.layout.ui_main); - accountUI = new AccountUI(context, parent, R.layout.ui_account); - versionUI = new VersionUI(context, parent, R.layout.ui_version); - manageUI = new ManageUI(context, parent, R.layout.ui_manage); - downloadUI = new DownloadUI(context, parent, R.layout.ui_download); - controllerUI = new ControllerUI(context, parent, R.layout.ui_controller); - multiplayerUI = new MultiplayerUI(context, parent, R.layout.ui_multiplayer); - settingUI = new SettingUI(context, parent, R.layout.ui_setting); - - allUIs = new FCLBaseUI[] { - mainUI, - accountUI, - versionUI, - manageUI, - downloadUI, - controllerUI, - multiplayerUI, - settingUI - }; - - for (FCLBaseUI ui : allUIs) { - ((FCLCommonUI) ui).addLoadingCallback(() -> { - loadedUI++; - if (loadedUI == allUIs.length) { - listener.onLoad(); - } - }); - } - } - - public Context getContext() { - return context; - } - - public FCLUILayout getParent() { - return parent; - } - - public MainUI getMainUI() { - return mainUI; - } - - public AccountUI getAccountUI() { - return accountUI; - } - - public VersionUI getVersionUI() { - return versionUI; - } - - public ManageUI getManageUI() { - return manageUI; - } - - public DownloadUI getDownloadUI() { - return downloadUI; - } - - public ControllerUI getControllerUI() { - return controllerUI; - } - - public MultiplayerUI getMultiplayerUI() { - return multiplayerUI; - } - - public SettingUI getSettingUI() { - return settingUI; - } - - public FCLBaseUI getCurrentUI() { - return currentUI; - } - - public void switchUI(FCLBaseUI ui) { - for (FCLBaseUI baseUI : allUIs) { - if (ui == baseUI) { - if (currentUI != null) { - currentUI.onStop(); - } - ui.onStart(); - currentUI = ui; - break; - } - } - } - - public void registerDefaultBackEvent(Runnable runnable) { - FCLBaseUI.setDefaultBackEvent(runnable); - } - - public void onBackPressed() { - if (currentUI != null) { - currentUI.onBackPressed(); - } - } - - public void onPause() { - for (FCLBaseUI baseUI : allUIs) { - baseUI.onPause(); - } - } - - public void onResume() { - for (FCLBaseUI baseUI : allUIs) { - baseUI.onResume(); - } - } -} diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.kt b/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.kt new file mode 100644 index 00000000..2c554918 --- /dev/null +++ b/FCL/src/main/java/com/tungsten/fcl/ui/UIManager.kt @@ -0,0 +1,98 @@ +package com.tungsten.fcl.ui + +import android.content.Context +import com.tungsten.fcl.R +import com.tungsten.fcl.ui.account.AccountUI +import com.tungsten.fcl.ui.controller.ControllerUI +import com.tungsten.fcl.ui.download.DownloadUI +import com.tungsten.fcl.ui.main.MainUI +import com.tungsten.fcl.ui.manage.ManageUI +import com.tungsten.fcl.ui.multiplayer.MultiplayerUI +import com.tungsten.fcl.ui.setting.SettingUI +import com.tungsten.fcl.ui.version.VersionUI +import com.tungsten.fclcore.util.Logging +import com.tungsten.fcllibrary.component.ui.FCLBaseUI +import com.tungsten.fcllibrary.component.ui.FCLCommonUI +import com.tungsten.fcllibrary.component.view.FCLUILayout +import java.util.logging.Level + +class UIManager(val context: Context, val parent: FCLUILayout) { + companion object { + @JvmStatic + lateinit var instance: UIManager + } + + private var initialized = false + lateinit var mainUI: MainUI + val accountUI: AccountUI by lazy { AccountUI(context, parent, R.layout.ui_account) } + val versionUI: VersionUI by lazy { VersionUI(context, parent, R.layout.ui_version) } + val manageUI: ManageUI by lazy { ManageUI(context, parent, R.layout.ui_manage) } + val downloadUI: DownloadUI by lazy { DownloadUI(context, parent, R.layout.ui_download) } + val controllerUI: ControllerUI by lazy { ControllerUI(context, parent, R.layout.ui_controller) } + val multiplayerUI: MultiplayerUI by lazy { + MultiplayerUI( + context, + parent, + R.layout.ui_multiplayer + ) + } + val settingUI: SettingUI by lazy { SettingUI(context, parent, R.layout.ui_setting) } + + private val allUIList = mutableListOf() + var currentUI: FCLBaseUI? = null + + fun init(listener: UIListener) { + if (initialized) { + Logging.LOG.log(Level.WARNING, "UIManager already initialized!") + return + } + instance = this + mainUI = MainUI(context, parent, R.layout.ui_main) + allUIList.add(mainUI) + mainUI.addLoadingCallback { + listener.onLoad() + } + } + + fun switchUI(ui: FCLCommonUI) { + var isFirstAdd = false + if (!allUIList.contains(ui)) { + isFirstAdd = true + allUIList.add(ui) + } + for (baseUI in allUIList) { + if (ui === baseUI) { + currentUI?.onStop() + if (isFirstAdd) { + ui.addLoadingCallback { + ui.onStart() + } + } else { + ui.onStart() + } + currentUI = ui + break + } + } + } + + fun registerDefaultBackEvent(runnable: Runnable?) { + FCLBaseUI.setDefaultBackEvent(runnable) + } + + fun onBackPressed() { + currentUI?.onBackPressed() + } + + fun onPause() { + for (baseUI in allUIList) { + baseUI.onPause() + } + } + + fun onResume() { + for (baseUI in allUIList) { + baseUI.onResume() + } + } +} \ No newline at end of file diff --git a/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java b/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java index 94f7b20f..557dae6e 100644 --- a/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java +++ b/FCL/src/main/java/com/tungsten/fcl/ui/manage/ManageUI.java @@ -68,6 +68,9 @@ public class ManageUI extends FCLMultiPageUI implements TabLayout.OnTabSelectedL return; } + if (pageManager == null) { + pageManager = new ManagePageManager(getContext(), container, ManagePageManager.PAGE_ID_MANAGE_MANAGE, null); + } loadVersion(getVersion(), getProfile()); }