diff --git a/src/org/geometerplus/android/fbreader/network/ItemsLoadingService.java b/src/org/geometerplus/android/fbreader/network/ItemsLoadingService.java index 2e91b5d4c..a25fb8d8f 100644 --- a/src/org/geometerplus/android/fbreader/network/ItemsLoadingService.java +++ b/src/org/geometerplus/android/fbreader/network/ItemsLoadingService.java @@ -19,17 +19,47 @@ package org.geometerplus.android.fbreader.network; +import android.app.Service; +import android.content.Context; +import android.content.Intent; import android.os.IBinder; import android.os.Handler; import android.os.Message; -import android.app.Service; -import android.content.Intent; import org.geometerplus.fbreader.network.NetworkTree; public class ItemsLoadingService extends Service { + private static final String KEY = "ItemsLoadingRunnable"; - public static final String ITEMS_LOADING_RUNNABLE_KEY = "org.geometerplus.android.fbreader.network.ItemsLoadingRunnable"; + static void start(Context context, NetworkTree tree, ItemsLoadingRunnable runnable) { + boolean doDownload = false; + synchronized (tree) { + if (tree.getUserData(KEY) == null) { + tree.setUserData(KEY, runnable); + doDownload = true; + } + } + if (doDownload) { + context.startService( + new Intent(context.getApplicationContext(), ItemsLoadingService.class) + .putExtra(Util.TREE_KEY_KEY, tree.getUniqueKey()) + ); + } + } + + static ItemsLoadingRunnable getRunnable(NetworkTree tree) { + return (ItemsLoadingRunnable)tree.getUserData(KEY); + } + + private static void removeRunnable(NetworkTree tree) { + synchronized (tree) { + ItemsLoadingRunnable runnable = (ItemsLoadingRunnable)tree.getUserData(KEY); + if (runnable != null) { + tree.setUserData(KEY, null); + runnable.runFinishHandler(); + } + } + } private volatile int myServiceCounter; @@ -54,18 +84,19 @@ public class ItemsLoadingService extends Service { super.onStart(intent, startId); doStart(); - final NetworkTree.Key key = (NetworkTree.Key)intent.getSerializableExtra(ITEMS_LOADING_RUNNABLE_KEY); - if (key == null) { + final NetworkTree tree = Util.getTreeFromIntent(intent); + if (tree == null) { doStop(); return; } - intent.removeExtra(ITEMS_LOADING_RUNNABLE_KEY); + intent.removeExtra(Util.TREE_KEY_KEY); if (!NetworkView.Instance().isInitialized()) { doStop(); return; } - final ItemsLoadingRunnable runnable = NetworkView.Instance().getItemsLoadingRunnable(key); + + final ItemsLoadingRunnable runnable = getRunnable(tree); if (runnable == null) { doStop(); return; @@ -74,8 +105,8 @@ public class ItemsLoadingService extends Service { final Handler finishHandler = new Handler() { public void handleMessage(Message message) { doStop(); + removeRunnable(tree); if (NetworkView.Instance().isInitialized()) { - NetworkView.Instance().removeItemsLoadingRunnable(key); NetworkView.Instance().fireModelChangedAsync(); } } diff --git a/src/org/geometerplus/android/fbreader/network/NetworkCatalogActions.java b/src/org/geometerplus/android/fbreader/network/NetworkCatalogActions.java index dcfb31726..406e5ef93 100644 --- a/src/org/geometerplus/android/fbreader/network/NetworkCatalogActions.java +++ b/src/org/geometerplus/android/fbreader/network/NetworkCatalogActions.java @@ -174,9 +174,9 @@ class NetworkCatalogActions extends NetworkTreeActions { item instanceof NetworkURLCatalogItem ? (NetworkURLCatalogItem)item : null; prepareOptionsItem(menu, RELOAD_ITEM_ID, - urlItem != null && - urlItem.getUrl(UrlInfo.Type.Catalog) != null && - !NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey()) + urlItem != null && + urlItem.getUrl(UrlInfo.Type.Catalog) != null && + ItemsLoadingService.getRunnable(tree) == null ); boolean signIn = false; @@ -438,9 +438,9 @@ class NetworkCatalogActions extends NetworkTreeActions { * 3) Remove unused messages (say, by timeout) */ final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, key); - NetworkView.Instance().startItemsLoading( + ItemsLoadingService.start( activity, - key, + tree, new ExpandCatalogRunnable(handler, tree, true, resumeNotLoad) ); processExtraData(activity, tree.Item.extraData(), new Runnable() { @@ -453,17 +453,16 @@ class NetworkCatalogActions extends NetworkTreeActions { } public void doReloadCatalog(NetworkBaseActivity activity, final NetworkCatalogTree tree) { - final NetworkTree.Key key = tree.getUniqueKey(); - if (NetworkView.Instance().containsItemsLoadingRunnable(key)) { + if (ItemsLoadingService.getRunnable(tree) != null) { return; } tree.ChildrenItems.clear(); tree.clear(); NetworkView.Instance().fireModelChangedAsync(); - final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, key); - NetworkView.Instance().startItemsLoading( + final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, tree.getUniqueKey()); + ItemsLoadingService.start( activity, - key, + tree, new ExpandCatalogRunnable(handler, tree, false, false) ); } diff --git a/src/org/geometerplus/android/fbreader/network/NetworkCatalogActivity.java b/src/org/geometerplus/android/fbreader/network/NetworkCatalogActivity.java index 35cf00559..60620856a 100644 --- a/src/org/geometerplus/android/fbreader/network/NetworkCatalogActivity.java +++ b/src/org/geometerplus/android/fbreader/network/NetworkCatalogActivity.java @@ -222,21 +222,25 @@ public class NetworkCatalogActivity extends NetworkBaseActivity implements UserR } } - private static NetworkTree.Key getLoadableNetworkTreeKey(NetworkTree tree) { - if ((tree instanceof NetworkAuthorTree || tree instanceof NetworkSeriesTree) - && tree.Parent instanceof NetworkTree) { - return getLoadableNetworkTreeKey((NetworkTree)tree.Parent); + private static NetworkTree getLoadableNetworkTree(NetworkTree tree) { + while (tree instanceof NetworkAuthorTree || tree instanceof NetworkSeriesTree) { + if (tree.Parent instanceof NetworkTree) { + tree = (NetworkTree)tree.Parent; + } else { + return null; + } } - return tree.getUniqueKey(); + return tree; } @Override public void onModelChanged() { runOnUiThread(new Runnable() { public void run() { - final NetworkView networkView = NetworkView.Instance(); - final NetworkTree.Key key = getLoadableNetworkTreeKey(myTree); - myInProgress = key != null && networkView.isInitialized() && networkView.containsItemsLoadingRunnable(key); + final NetworkTree tree = getLoadableNetworkTree(myTree); + myInProgress = + tree != null && + ItemsLoadingService.getRunnable(tree) != null; getListView().invalidateViews(); /* @@ -261,12 +265,9 @@ public class NetworkCatalogActivity extends NetworkBaseActivity implements UserR } private void doStopLoading() { - if (NetworkView.Instance().isInitialized()) { - final ItemsLoadingRunnable runnable = - NetworkView.Instance().getItemsLoadingRunnable(myTree.getUniqueKey()); - if (runnable != null) { - runnable.interruptLoading(); - } + final ItemsLoadingRunnable runnable = ItemsLoadingService.getRunnable(myTree); + if (runnable != null) { + runnable.interruptLoading(); } } diff --git a/src/org/geometerplus/android/fbreader/network/NetworkLibraryActivity.java b/src/org/geometerplus/android/fbreader/network/NetworkLibraryActivity.java index dc2fb0051..dc1e482e6 100644 --- a/src/org/geometerplus/android/fbreader/network/NetworkLibraryActivity.java +++ b/src/org/geometerplus/android/fbreader/network/NetworkLibraryActivity.java @@ -200,13 +200,9 @@ public class NetworkLibraryActivity extends NetworkBaseActivity { } private static boolean searchIsInProgress() { - final NetworkView nView = NetworkView.Instance(); - return - nView != null && - nView.isInitialized() && - nView.containsItemsLoadingRunnable( - NetworkLibrary.Instance().getSearchItemTree().getUniqueKey() - ); + return ItemsLoadingService.getRunnable( + NetworkLibrary.Instance().getSearchItemTree() + ) != null; } @Override diff --git a/src/org/geometerplus/android/fbreader/network/NetworkSearchActivity.java b/src/org/geometerplus/android/fbreader/network/NetworkSearchActivity.java index d87b60c15..7efa0da84 100644 --- a/src/org/geometerplus/android/fbreader/network/NetworkSearchActivity.java +++ b/src/org/geometerplus/android/fbreader/network/NetworkSearchActivity.java @@ -156,7 +156,7 @@ public class NetworkSearchActivity extends Activity { final SearchItemTree tree = library.getSearchItemTree(); if (tree == null || - NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey())) { + ItemsLoadingService.getRunnable(tree) != null) { return; } @@ -167,10 +167,8 @@ public class NetworkSearchActivity extends Activity { NetworkView.Instance().fireModelChangedAsync(); final SearchHandler handler = new SearchHandler(tree); - NetworkView.Instance().startItemsLoading( - this, - tree.getUniqueKey(), - new SearchRunnable(handler, pattern) + ItemsLoadingService.start( + this, tree, new SearchRunnable(handler, pattern) ); Util.openTree(this, tree); } diff --git a/src/org/geometerplus/android/fbreader/network/NetworkView.java b/src/org/geometerplus/android/fbreader/network/NetworkView.java index 24953e498..560a65630 100644 --- a/src/org/geometerplus/android/fbreader/network/NetworkView.java +++ b/src/org/geometerplus/android/fbreader/network/NetworkView.java @@ -134,46 +134,8 @@ class NetworkView { * Code for loading network items (running items-loading service and managing items-loading runnables). */ - private final HashMap myItemsLoadingRunnables = - new HashMap(); - - public void startItemsLoading(Context context, NetworkTree.Key key, ItemsLoadingRunnable runnable) { - boolean doDownload = false; - synchronized (myItemsLoadingRunnables) { - if (!myItemsLoadingRunnables.containsKey(key)) { - myItemsLoadingRunnables.put(key, runnable); - doDownload = true; - } - } - if (doDownload) { - context.startService( - new Intent(context.getApplicationContext(), ItemsLoadingService.class) - .putExtra(ItemsLoadingService.ITEMS_LOADING_RUNNABLE_KEY, key) - ); - } - } - - ItemsLoadingRunnable getItemsLoadingRunnable(NetworkTree.Key key) { - synchronized (myItemsLoadingRunnables) { - return myItemsLoadingRunnables.get(key); - } - } - - void removeItemsLoadingRunnable(NetworkTree.Key key) { - synchronized (myItemsLoadingRunnables) { - ItemsLoadingRunnable runnable = myItemsLoadingRunnables.remove(key); - if (runnable != null) { - runnable.runFinishHandler(); - } - } - } - - public final boolean containsItemsLoadingRunnable(NetworkTree.Key key) { - return getItemsLoadingRunnable(key) != null; - } - public void tryResumeLoading(NetworkBaseActivity activity, NetworkCatalogTree tree, Runnable expandRunnable) { - final ItemsLoadingRunnable runnable = getItemsLoadingRunnable(tree.getUniqueKey()); + final ItemsLoadingRunnable runnable = ItemsLoadingService.getRunnable(tree); if (runnable != null && runnable.tryResumeLoading()) { Util.openTree(activity, tree); return; diff --git a/src/org/geometerplus/android/fbreader/network/SearchItemActions.java b/src/org/geometerplus/android/fbreader/network/SearchItemActions.java index 043cf73ff..123ed7b94 100644 --- a/src/org/geometerplus/android/fbreader/network/SearchItemActions.java +++ b/src/org/geometerplus/android/fbreader/network/SearchItemActions.java @@ -50,7 +50,7 @@ class SearchItemActions extends NetworkTreeActions { public void buildContextMenu(Activity activity, ContextMenu menu, NetworkTree tree) { menu.setHeaderTitle(tree.getName()); - final boolean isLoading = NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey()); + final boolean isLoading = ItemsLoadingService.getRunnable(tree) != null; if (!isLoading) { addMenuItem(menu, RUN_SEARCH_ITEM_ID, "search"); @@ -61,7 +61,7 @@ class SearchItemActions extends NetworkTreeActions { @Override public int getDefaultActionCode(NetworkBaseActivity activity, NetworkTree tree) { - final boolean isLoading = NetworkView.Instance().containsItemsLoadingRunnable(tree.getUniqueKey()); + final boolean isLoading = ItemsLoadingService.getRunnable(tree) != null; if (!isLoading) { return RUN_SEARCH_ITEM_ID; } diff --git a/src/org/geometerplus/android/fbreader/network/Util.java b/src/org/geometerplus/android/fbreader/network/Util.java index 8989c0559..dae3df613 100644 --- a/src/org/geometerplus/android/fbreader/network/Util.java +++ b/src/org/geometerplus/android/fbreader/network/Util.java @@ -232,7 +232,7 @@ abstract class Util implements UserRegistrationConstants { } } - private static final String TREE_KEY_KEY = "org.geometerplus.android.fbreader.network.TreeKey"; + static final String TREE_KEY_KEY = "org.geometerplus.android.fbreader.network.TreeKey"; static void openTree(Context context, NetworkTree tree) { final Class clz = tree instanceof NetworkBookTree diff --git a/src/org/geometerplus/fbreader/network/NetworkBookItem.java b/src/org/geometerplus/fbreader/network/NetworkBookItem.java index 58466a89f..18e461c4f 100644 --- a/src/org/geometerplus/fbreader/network/NetworkBookItem.java +++ b/src/org/geometerplus/fbreader/network/NetworkBookItem.java @@ -109,6 +109,10 @@ public class NetworkBookItem extends NetworkItem { IndexInSeries = indexInSeries; } + public boolean isFullyLoaded() { + return true; + } + public void loadFullInformation() throws ZLNetworkException { } diff --git a/src/org/geometerplus/fbreader/network/NetworkTree.java b/src/org/geometerplus/fbreader/network/NetworkTree.java index 8c5d1f319..4de3b5415 100644 --- a/src/org/geometerplus/fbreader/network/NetworkTree.java +++ b/src/org/geometerplus/fbreader/network/NetworkTree.java @@ -19,8 +19,7 @@ package org.geometerplus.fbreader.network; -import java.util.LinkedList; -import java.util.Set; +import java.util.*; import java.io.Serializable; import org.geometerplus.zlibrary.core.image.ZLImage; @@ -67,6 +66,9 @@ public abstract class NetworkTree extends FBTree { } } + private Key myKey; + private Map myUserData; + protected NetworkTree() { super(); } @@ -123,10 +125,8 @@ public abstract class NetworkTree extends FBTree { return null; } - public abstract NetworkItem getHoldedItem(); - private Key myKey; /** * Returns unique identifier which can be used in NetworkView methods * @return unique Key instance @@ -141,6 +141,21 @@ public abstract class NetworkTree extends FBTree { return myKey; } + public final synchronized void setUserData(String key, Object data) { + if (myUserData == null) { + myUserData = new HashMap(); + } + if (data != null) { + myUserData.put(key, data); + } else { + myUserData.remove(key); + } + } + + public final synchronized Object getUserData(String key) { + return myUserData != null ? myUserData.get(key) : null; + } + /** * Returns id used as a part of unique key above. This string must be * not null diff --git a/src/org/geometerplus/fbreader/network/opds/OPDSBookItem.java b/src/org/geometerplus/fbreader/network/opds/OPDSBookItem.java index 37c224f96..032d8541a 100644 --- a/src/org/geometerplus/fbreader/network/opds/OPDSBookItem.java +++ b/src/org/geometerplus/fbreader/network/opds/OPDSBookItem.java @@ -208,6 +208,11 @@ public class OPDSBookItem extends NetworkBookItem implements OPDSConstants { private volatile boolean myInformationIsFull; + @Override + public synchronized boolean isFullyLoaded() { + return myInformationIsFull || getUrl(UrlInfo.Type.SingleEntry) == null; + } + @Override public synchronized void loadFullInformation() throws ZLNetworkException { if (myInformationIsFull) {