From 2941cf8d94bb374b4a0d496cd39e49e9be62c555 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 17 Nov 2021 21:49:51 +0100 Subject: [PATCH] Android: Make GameFileCacheManager use LiveData, part 2 Gets rid some uses of the deprecated LocalBroadcastManager. One note about the changes in GameFileCacheManager itself: The change from compareAndSet to getValue followed by setValue is actually safe, because startLoad and startRescan only run from the main thread, and only the main thread ever sets the flags to true. So it's impossible for any other thread to change the flag in between the getValue and the setValue. --- .../activities/AppLinkActivity.java | 23 ++------- .../services/GameFileCacheManager.java | 50 +++++++------------ .../dolphinemu/ui/main/MainPresenter.java | 30 +++-------- .../dolphinemu/ui/main/TvMainActivity.java | 2 +- .../ui/platform/PlatformGamesFragment.java | 2 +- 5 files changed, 31 insertions(+), 76 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java index 01a87fdd3aef..ed5dac911e21 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AppLinkActivity.java @@ -2,16 +2,12 @@ package org.dolphinemu.dolphinemu.activities; -import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import android.util.Log; import androidx.fragment.app.FragmentActivity; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.services.GameFileCacheManager; @@ -69,22 +65,13 @@ private void initResources() mAfterDirectoryInitializationRunner = new AfterDirectoryInitializationRunner(); mAfterDirectoryInitializationRunner.run(this, true, () -> tryPlay(playAction)); - IntentFilter gameFileCacheIntentFilter = new IntentFilter(GameFileCacheManager.DONE_LOADING); - - BroadcastReceiver gameFileCacheReceiver = new BroadcastReceiver() + GameFileCacheManager.isLoading().observe(this, (isLoading) -> { - @Override - public void onReceive(Context context, Intent intent) + if (!isLoading && DirectoryInitialization.areDolphinDirectoriesReady()) { - if (DirectoryInitialization.areDolphinDirectoriesReady()) - { - tryPlay(playAction); - } + tryPlay(playAction); } - }; - - LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this); - broadcastManager.registerReceiver(gameFileCacheReceiver, gameFileCacheIntentFilter); + }); DirectoryInitialization.start(this); GameFileCacheManager.startLoad(this); @@ -110,7 +97,7 @@ private void tryPlay(AppLinkHelper.PlayAction action) // If game == null and the load isn't done, wait for the next GameFileCacheService broadcast. // If game == null and the load is done, call play with a null game, making us exit in failure. - if (game != null || !GameFileCacheManager.isLoading()) + if (game != null || !GameFileCacheManager.isLoading().getValue()) { play(action, game); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheManager.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheManager.java index 5ff51c1b432c..d08d28f98987 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheManager.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/GameFileCacheManager.java @@ -3,13 +3,10 @@ package org.dolphinemu.dolphinemu.services; import android.content.Context; -import android.content.Intent; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.model.GameFile; import org.dolphinemu.dolphinemu.model.GameFileCache; import org.dolphinemu.dolphinemu.ui.platform.Platform; @@ -20,27 +17,19 @@ import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; /** * Loads game list data on a separate thread. */ public final class GameFileCacheManager { - /** - * This is broadcast when the service is done with all requested work, regardless of whether - * the contents of the cache actually changed. (Maybe the cache was already up to date.) - */ - public static final String DONE_LOADING = - "org.dolphinemu.dolphinemu.GAME_FILE_CACHE_DONE_LOADING"; - private static GameFileCache gameFileCache = null; private static final MutableLiveData gameFiles = new MutableLiveData<>(new GameFile[]{}); private static final ExecutorService executor = Executors.newFixedThreadPool(1); - private static final AtomicBoolean loadInProgress = new AtomicBoolean(false); - private static final AtomicBoolean rescanInProgress = new AtomicBoolean(false); + private static final MutableLiveData loadInProgress = new MutableLiveData<>(false); + private static final MutableLiveData rescanInProgress = new MutableLiveData<>(false); private GameFileCacheManager() { @@ -108,19 +97,24 @@ public static String[] findSecondDiscAndGetPaths(GameFile gameFile) } /** - * Returns true if in the process of either loading the cache or rescanning. + * Returns true if in the process of loading the cache for the first time. */ - public static boolean isLoading() + public static LiveData isLoading() { - return loadInProgress.get(); + return loadInProgress; } /** * Returns true if in the process of rescanning. */ - public static boolean isRescanning() + public static LiveData isRescanning() { - return rescanInProgress.get(); + return rescanInProgress; + } + + public static boolean isLoadingOrRescanning() + { + return loadInProgress.getValue() || rescanInProgress.getValue(); } /** @@ -130,8 +124,9 @@ public static boolean isRescanning() */ public static void startLoad(Context context) { - if (loadInProgress.compareAndSet(false, true)) + if (!loadInProgress.getValue()) { + loadInProgress.setValue(true); new AfterDirectoryInitializationRunner().run(context, false, () -> executor.execute(GameFileCacheManager::load)); } @@ -144,8 +139,9 @@ public static void startLoad(Context context) */ public static void startRescan(Context context) { - if (rescanInProgress.compareAndSet(false, true)) + if (!rescanInProgress.getValue()) { + rescanInProgress.setValue(true); new AfterDirectoryInitializationRunner().run(context, false, () -> executor.execute(GameFileCacheManager::rescan)); } @@ -194,9 +190,7 @@ private static void load() } } - loadInProgress.set(false); - if (!rescanInProgress.get()) - sendBroadcast(DONE_LOADING); + loadInProgress.postValue(false); } /** @@ -232,9 +226,7 @@ private static void rescan() } } - rescanInProgress.set(false); - if (!loadInProgress.get()) - sendBroadcast(DONE_LOADING); + rescanInProgress.postValue(false); } private static void updateGameFileArray() @@ -243,10 +235,4 @@ private static void updateGameFileArray() Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle())); gameFiles.postValue(gameFilesTemp); } - - private static void sendBroadcast(String action) - { - LocalBroadcastManager.getInstance(DolphinApplication.getAppContext()) - .sendBroadcast(new Intent(action)); - } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index 13caef1fc0ac..778e38f6a17d 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -2,16 +2,14 @@ package org.dolphinemu.dolphinemu.ui.main; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.net.Uri; import androidx.appcompat.app.AlertDialog; import androidx.core.app.ComponentActivity; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.lifecycle.Observer; import org.dolphinemu.dolphinemu.BuildConfig; import org.dolphinemu.dolphinemu.R; @@ -43,7 +41,6 @@ public final class MainPresenter private final MainView mView; private final ComponentActivity mActivity; - private BroadcastReceiver mBroadcastReceiver = null; private String mDirToAdd; public MainPresenter(MainView view, ComponentActivity activity) @@ -59,30 +56,16 @@ public void onCreate() GameFileCacheManager.getGameFiles().observe(mActivity, (gameFiles) -> mView.showGames()); - IntentFilter filter = new IntentFilter(); - filter.addAction(GameFileCacheManager.DONE_LOADING); - mBroadcastReceiver = new BroadcastReceiver() + Observer refreshObserver = (isLoading) -> { - @Override - public void onReceive(Context context, Intent intent) - { - switch (intent.getAction()) - { - case GameFileCacheManager.DONE_LOADING: - mView.setRefreshing(false); - break; - } - } + mView.setRefreshing(GameFileCacheManager.isLoadingOrRescanning()); }; - LocalBroadcastManager.getInstance(mActivity).registerReceiver(mBroadcastReceiver, filter); + GameFileCacheManager.isLoading().observe(mActivity, refreshObserver); + GameFileCacheManager.isRescanning().observe(mActivity, refreshObserver); } public void onDestroy() { - if (mBroadcastReceiver != null) - { - LocalBroadcastManager.getInstance(mActivity).unregisterReceiver(mBroadcastReceiver); - } } public void onFabClick() @@ -138,11 +121,10 @@ public void onResume() mDirToAdd = null; } - if (sShouldRescanLibrary && !GameFileCacheManager.isRescanning()) + if (sShouldRescanLibrary && !GameFileCacheManager.isRescanning().getValue()) { new AfterDirectoryInitializationRunner().run(mActivity, false, () -> { - mView.setRefreshing(true); GameFileCacheManager.startRescan(mActivity); }); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java index 15f8c866e7e3..58f3bbafb756 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java @@ -122,7 +122,7 @@ void setupUI() mSwipeRefresh.setOnRefreshListener(this); - setRefreshing(GameFileCacheManager.isLoading()); + setRefreshing(GameFileCacheManager.isLoadingOrRescanning()); final FragmentManager fragmentManager = getSupportFragmentManager(); mBrowseFragment = new BrowseSupportFragment(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java index 641802df54fa..feb08adfcd50 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/platform/PlatformGamesFragment.java @@ -73,7 +73,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8)); - setRefreshing(GameFileCacheManager.isLoading()); + setRefreshing(GameFileCacheManager.isLoadingOrRescanning()); showGames(); }