Skip to content

Commit

Permalink
Android: Make GameFileCacheManager use LiveData, part 2
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
JosJuice committed Nov 17, 2021
1 parent 857963b commit 2941cf8
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 76 deletions.
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down
Expand Up @@ -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;
Expand All @@ -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<GameFile[]> 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<Boolean> loadInProgress = new MutableLiveData<>(false);
private static final MutableLiveData<Boolean> rescanInProgress = new MutableLiveData<>(false);

private GameFileCacheManager()
{
Expand Down Expand Up @@ -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<Boolean> isLoading()
{
return loadInProgress.get();
return loadInProgress;
}

/**
* Returns true if in the process of rescanning.
*/
public static boolean isRescanning()
public static LiveData<Boolean> isRescanning()
{
return rescanInProgress.get();
return rescanInProgress;
}

public static boolean isLoadingOrRescanning()
{
return loadInProgress.getValue() || rescanInProgress.getValue();
}

/**
Expand All @@ -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));
}
Expand All @@ -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));
}
Expand Down Expand Up @@ -194,9 +190,7 @@ private static void load()
}
}

loadInProgress.set(false);
if (!rescanInProgress.get())
sendBroadcast(DONE_LOADING);
loadInProgress.postValue(false);
}

/**
Expand Down Expand Up @@ -232,9 +226,7 @@ private static void rescan()
}
}

rescanInProgress.set(false);
if (!loadInProgress.get())
sendBroadcast(DONE_LOADING);
rescanInProgress.postValue(false);
}

private static void updateGameFileArray()
Expand All @@ -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));
}
}
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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<Boolean> 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()
Expand Down Expand Up @@ -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);
});
}
Expand Down
Expand Up @@ -122,7 +122,7 @@ void setupUI()

mSwipeRefresh.setOnRefreshListener(this);

setRefreshing(GameFileCacheManager.isLoading());
setRefreshing(GameFileCacheManager.isLoadingOrRescanning());

final FragmentManager fragmentManager = getSupportFragmentManager();
mBrowseFragment = new BrowseSupportFragment();
Expand Down
Expand Up @@ -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();
}
Expand Down

0 comments on commit 2941cf8

Please sign in to comment.