diff --git a/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java b/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java index 47ff86264..d2e1517df 100644 --- a/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java +++ b/clients/android/NewsBlur/src/com/newsblur/database/BlurDatabaseHelper.java @@ -108,11 +108,13 @@ public class BlurDatabaseHelper { } public void cleanupStories(boolean keepOldStories) { + // story cleanup happens at a low priority in the background. the goal here is to lock + // the DB for as short a time as possible, not absolute efficiency. for (String feedId : getAllFeeds()) { String q = "DELETE FROM " + DatabaseConstants.STORY_TABLE + " WHERE " + DatabaseConstants.STORY_ID + " IN " + "( SELECT " + DatabaseConstants.STORY_ID + " FROM " + DatabaseConstants.STORY_TABLE + - " WHERE " + DatabaseConstants.STORY_READ + " = 1" + + " WHERE " + DatabaseConstants.STORY_READ + " = 1" + // don't cleanup unreads " AND " + DatabaseConstants.STORY_FEED_ID + " = " + feedId + " ORDER BY " + DatabaseConstants.STORY_TIMESTAMP + " DESC" + " LIMIT -1 OFFSET " + (keepOldStories ? AppConstants.MAX_READ_STORIES_STORED : 0) + diff --git a/clients/android/NewsBlur/src/com/newsblur/service/CleanupService.java b/clients/android/NewsBlur/src/com/newsblur/service/CleanupService.java new file mode 100644 index 000000000..ba4ef0ac5 --- /dev/null +++ b/clients/android/NewsBlur/src/com/newsblur/service/CleanupService.java @@ -0,0 +1,44 @@ +package com.newsblur.service; + +import android.util.Log; + +import com.newsblur.util.ImageCache; +import com.newsblur.util.PrefsUtils; + +public class CleanupService extends SubService { + + private static volatile boolean Running = false; + + public CleanupService(NBSyncService parent) { + super(parent); + } + + @Override + protected void exec() { + if (!PrefsUtils.isTimeToCleanup(parent)) return; + + gotWork(); + + // do cleanup + parent.dbHelper.cleanupStories(PrefsUtils.isKeepOldStories(parent)); + parent.dbHelper.cleanupStoryText(); + ImageCache imageCache = new ImageCache(parent); + imageCache.cleanup(parent.dbHelper.getAllStoryImages()); + + PrefsUtils.updateLastCleanupTime(parent); + } + + public static boolean running() { + return Running; + } + @Override + protected void setRunning(boolean running) { + Running = running; + } + @Override + protected boolean isRunning() { + return Running; + } + +} + diff --git a/clients/android/NewsBlur/src/com/newsblur/service/NBSyncService.java b/clients/android/NewsBlur/src/com/newsblur/service/NBSyncService.java index 4717f2333..8b37cead1 100644 --- a/clients/android/NewsBlur/src/com/newsblur/service/NBSyncService.java +++ b/clients/android/NewsBlur/src/com/newsblur/service/NBSyncService.java @@ -77,7 +77,6 @@ public class NBSyncService extends Service { private static final Object PENDING_FEED_MUTEX = new Object(); private volatile static boolean ActionsRunning = false; - private volatile static boolean CleanupRunning = false; private volatile static boolean FFSyncRunning = false; private volatile static boolean StorySyncRunning = false; private volatile static boolean HousekeepingRunning = false; @@ -126,6 +125,7 @@ public class NBSyncService extends Service { Set orphanFeedIds; private ExecutorService primaryExecutor; + CleanupService cleanupService; OriginalTextService originalTextService; UnreadsService unreadsService; ImagePrefetchService imagePrefetchService; @@ -155,6 +155,7 @@ public class NBSyncService extends Service { if (apiManager == null) { apiManager = new APIManager(this); dbHelper = new BlurDatabaseHelper(this); + cleanupService = new CleanupService(this); originalTextService = new OriginalTextService(this); unreadsService = new UnreadsService(this); imagePrefetchService = new ImagePrefetchService(this); @@ -362,9 +363,6 @@ public class NBSyncService extends Service { * unread hashes. Doing this resets pagination on the server! */ private void syncMetadata(int startId) { - if (stopSync()) return; - if (ActMode != ActivationMode.ALL) return; - if (DoFeedsFolders || PrefsUtils.isTimeToAutoSync(this)) { PrefsUtils.updateLastSyncTime(this); DoFeedsFolders = false; @@ -372,16 +370,6 @@ public class NBSyncService extends Service { return; } - // cleanup is expensive, so do it as part of the metadata sync - CleanupRunning = true; - NbActivity.updateAllActivities(false); - dbHelper.cleanupStories(PrefsUtils.isKeepOldStories(this)); - dbHelper.cleanupStoryText(); - imagePrefetchService.imageCache.cleanup(dbHelper.getAllStoryImages()); - CleanupRunning = false; - NbActivity.updateAllActivities(false); - - // cleanup may have taken a while, so re-check our running status if (stopSync()) return; if (ActMode != ActivationMode.ALL) return; @@ -461,6 +449,7 @@ public class NBSyncService extends Service { lastFFWriteMillis = System.currentTimeMillis() - startTime; lastFeedCount = feedValues.size(); + cleanupService.start(startId); unreadsService.start(startId); UnreadsService.doMetadata(); @@ -690,7 +679,7 @@ public class NBSyncService extends Service { * Is the main feed/folder list sync running? */ public static boolean isFeedFolderSyncRunning() { - return (HousekeepingRunning || ActionsRunning || RecountsRunning || FFSyncRunning || CleanupRunning || UnreadsService.running() || StorySyncRunning || OriginalTextService.running() || ImagePrefetchService.running()); + return (HousekeepingRunning || ActionsRunning || RecountsRunning || FFSyncRunning || CleanupService.running() || UnreadsService.running() || StorySyncRunning || OriginalTextService.running() || ImagePrefetchService.running()); } /** @@ -706,7 +695,7 @@ public class NBSyncService extends Service { if (HousekeepingRunning) return context.getResources().getString(R.string.sync_status_housekeeping); if (ActionsRunning||RecountsRunning) return context.getResources().getString(R.string.sync_status_actions); if (FFSyncRunning) return context.getResources().getString(R.string.sync_status_ffsync); - if (CleanupRunning) return context.getResources().getString(R.string.sync_status_cleanup); + if (CleanupService.running()) return context.getResources().getString(R.string.sync_status_cleanup); if (StorySyncRunning) return context.getResources().getString(R.string.sync_status_stories); if (UnreadsService.running()) return String.format(context.getResources().getString(R.string.sync_status_unreads), UnreadsService.getPendingCount()); if (OriginalTextService.running()) return String.format(context.getResources().getString(R.string.sync_status_text), OriginalTextService.getPendingCount()); @@ -819,6 +808,7 @@ public class NBSyncService extends Service { try { if (AppConstants.VERBOSE_LOG) Log.d(this.getClass().getName(), "onDestroy - stopping execution"); HaltNow = true; + if (cleanupService != null) cleanupService.shutdown(); if (unreadsService != null) unreadsService.shutdown(); if (originalTextService != null) originalTextService.shutdown(); if (imagePrefetchService != null) imagePrefetchService.shutdown(); diff --git a/clients/android/NewsBlur/src/com/newsblur/util/AppConstants.java b/clients/android/NewsBlur/src/com/newsblur/util/AppConstants.java index c9f4916fe..cba3b5da7 100644 --- a/clients/android/NewsBlur/src/com/newsblur/util/AppConstants.java +++ b/clients/android/NewsBlur/src/com/newsblur/util/AppConstants.java @@ -29,6 +29,9 @@ public class AppConstants { // how often to rebuild the DB public static final long VACUUM_TIME_MILLIS = 12L * 60L * 60L * 1000L; + // how often to clean up the DB + public static final long CLEANUP_TIME_MILLIS = 2L * 60L * 60L * 1000L; + // how often to trigger the BG service. slightly longer than how often we will find new stories, // to account for the fact that it is approximate, and missing a cycle is bad. public static final long BG_SERVICE_CYCLE_MILLIS = AUTO_SYNC_TIME_MILLIS + 30L * 1000L; diff --git a/clients/android/NewsBlur/src/com/newsblur/util/PrefConstants.java b/clients/android/NewsBlur/src/com/newsblur/util/PrefConstants.java index e284e1ded..55876349e 100644 --- a/clients/android/NewsBlur/src/com/newsblur/util/PrefConstants.java +++ b/clients/android/NewsBlur/src/com/newsblur/util/PrefConstants.java @@ -62,5 +62,7 @@ public class PrefConstants { public static final String LAST_VACUUM_TIME = "last_vacuum_time"; + public static final String LAST_CLEANUP_TIME = "last_cleanup_time"; + public static final String VOLUME_KEY_NAVIGATION = "volume_key_navigation"; } diff --git a/clients/android/NewsBlur/src/com/newsblur/util/PrefsUtils.java b/clients/android/NewsBlur/src/com/newsblur/util/PrefsUtils.java index e487b1916..9a572b6f7 100644 --- a/clients/android/NewsBlur/src/com/newsblur/util/PrefsUtils.java +++ b/clients/android/NewsBlur/src/com/newsblur/util/PrefsUtils.java @@ -242,6 +242,17 @@ public class PrefsUtils { prefs.edit().putLong(PrefConstants.LAST_VACUUM_TIME, (new Date()).getTime()).commit(); } + public static boolean isTimeToCleanup(Context context) { + SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0); + long lastTime = prefs.getLong(PrefConstants.LAST_CLEANUP_TIME, 1L); + return ( (lastTime + AppConstants.CLEANUP_TIME_MILLIS) < (new Date()).getTime() ); + } + + public static void updateLastCleanupTime(Context context) { + SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0); + prefs.edit().putLong(PrefConstants.LAST_CLEANUP_TIME, (new Date()).getTime()).commit(); + } + public static StoryOrder getStoryOrderForFeed(Context context, String feedId) { SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0); return StoryOrder.valueOf(prefs.getString(PrefConstants.FEED_STORY_ORDER_PREFIX + feedId, getDefaultStoryOrder(prefs).toString()));