Feat[icon]: icon cache cleaner

This commit is contained in:
artdeell 2023-08-18 19:39:44 +03:00 committed by ArtDev
parent e0c64219bc
commit ecbbbfcc4d
5 changed files with 94 additions and 1 deletions

View File

@ -32,6 +32,7 @@ import net.kdt.pojavlaunch.extra.ExtraListener;
import net.kdt.pojavlaunch.fragments.SelectAuthFragment;
import net.kdt.pojavlaunch.modloaders.modpacks.ModloaderInstallTracker;
import net.kdt.pojavlaunch.modloaders.modpacks.imagecache.IconCacheJanitor;
import net.kdt.pojavlaunch.multirt.MultiRTConfigDialog;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceFragment;
@ -154,6 +155,7 @@ public class LauncherActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pojav_launcher);
IconCacheJanitor.runJanitor();
getWindow().setBackgroundDrawable(null);
bindViews();
ProgressKeeper.addTaskCountListener((mProgressServiceKeeper = new ProgressServiceKeeper(this)));

View File

@ -26,6 +26,7 @@ class DownloadImageTask implements Runnable {
public boolean runCatching() {
try {
IconCacheJanitor.waitForJanitorToFinish();
DownloadUtils.downloadFile(mParentTask.imageUrl, mParentTask.cacheFile);
return true;
}catch (IOException e) {

View File

@ -0,0 +1,86 @@
package net.kdt.pojavlaunch.modloaders.modpacks.imagecache;
import android.util.Log;
import net.kdt.pojavlaunch.PojavApplication;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* This image is intended to keep the mod icon cache tidy (aka under 100 megabytes)
*/
public class IconCacheJanitor implements Runnable{
public static final long CACHE_SIZE_LIMIT = 104857600; // The cache size limit, 100 megabytes
public static final long CACHE_BRINGDOWN = 52428800; // The size to which the cache should be brought
// in case of an overflow, 50 mb
private static Future<?> sJanitorFuture;
private static boolean sJanitorRan = false;
private IconCacheJanitor() {
// don't allow others to create this
}
@Override
public void run() {
File modIconCachePath = ModIconCache.getImageCachePath();
if(!modIconCachePath.isDirectory() || !modIconCachePath.canRead()) return;
File[] modIconFiles = modIconCachePath.listFiles();
if(modIconFiles == null) return;
ArrayList<File> writableModIconFiles = new ArrayList<>(modIconFiles.length);
long directoryFileSize = 0;
for(File modIconFile : modIconFiles) {
if(!modIconFile.isFile() || !modIconFile.canRead()) continue;
directoryFileSize += modIconFile.length();
if(!modIconFile.canWrite()) continue;
writableModIconFiles.add(modIconFile);
}
if(directoryFileSize < CACHE_SIZE_LIMIT) {
Log.i("IconCacheJanitor", "Skipping cleanup because there's not enough to clean up");
return;
}
Arrays.sort(modIconFiles,
(x,y)-> Long.compare(y.lastModified(), x.lastModified())
);
int filesCleanedUp = 0;
for(File modFile : writableModIconFiles) {
if(directoryFileSize < CACHE_BRINGDOWN) break;
long modFileSize = modFile.length();
if(modFile.delete()) {
directoryFileSize -= modFileSize;
filesCleanedUp++;
}
}
Log.i("IconCacheJanitor", "Cleaned up "+filesCleanedUp+ " files");
synchronized (IconCacheJanitor.class) {
sJanitorFuture = null;
sJanitorRan = true;
}
}
/**
* Runs the janitor task, unless there was one running already or one has ran already
*/
public static void runJanitor() {
synchronized (IconCacheJanitor.class) {
if (sJanitorFuture != null || sJanitorRan) return;
sJanitorFuture = PojavApplication.sExecutorService.submit(new IconCacheJanitor());
}
}
/**
* Waits for the janitor task to finish, if there is one running already
* Note that the thread waiting must not be interrupted.
*/
public static void waitForJanitorToFinish() {
synchronized (IconCacheJanitor.class) {
if (sJanitorFuture == null) return;
try {
sJanitorFuture.get();
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException("Should not happen!", e);
}
}
}
}

View File

@ -27,13 +27,16 @@ public class ModIconCache {
File cachePath;
private final List<WeakReference<ImageReceiver>> mCancelledReceivers = new ArrayList<>();
public ModIconCache() {
cachePath = new File(Tools.DIR_CACHE, "mod_icons");
cachePath = getImageCachePath();
if(!cachePath.exists() && !cachePath.isFile() && Tools.DIR_CACHE.canWrite()) {
if(!cachePath.mkdirs())
throw new RuntimeException("Failed to create icon cache directory");
}
}
static File getImageCachePath() {
return new File(Tools.DIR_CACHE, "mod_icons");
}
/**
* Get an image for a mod with the associated tag and URL to download it in case if its not cached

View File

@ -30,6 +30,7 @@ public class ReadFromDiskTask implements Runnable {
return;
}
if(cacheFile.canRead()) {
IconCacheJanitor.waitForJanitorToFinish();
Bitmap bitmap = BitmapFactory.decodeFile(cacheFile.getAbsolutePath());
if(bitmap != null) {
Tools.runOnUiThread(()->{