mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-05 02:39:23 +02:00
Loading is interrupted on leaving catalog
git-svn-id: https://only.mawhrin.net/repos/FBReaderJ/trunk@1369 6a642e6f-84f6-412e-ac94-c4a38d5a04b0
This commit is contained in:
parent
377923f68b
commit
70901bcf3c
8 changed files with 203 additions and 81 deletions
|
@ -16,8 +16,8 @@ DONE Network library: Объединять книги по сериям
|
|||
NP: а где это происходит???
|
||||
** изменить вид библиотеки -- вместо дерева -- последовательные view без сдвига вправо (как в маркете)
|
||||
DONE сделать пункт Search в дереве
|
||||
** при нажатии на кнопку 'Esc' -- возвращаться к предыдущему view + прерывать загрузку, если она еще идет;
|
||||
** прерывание вручную умирает => загружать заново после прерывания
|
||||
DONE при нажатии на кнопку 'Esc' -- возвращаться к предыдущему view + прерывать загрузку, если она еще идет;
|
||||
DONE прерывание вручную умирает => загружать заново после прерывания
|
||||
* соответственно, каталог должен иметь не 2 состояния -- загружен/не загружен, а загружен полностью/не полностью/не загружен;
|
||||
в случае загрузки не полностью можно при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что подделены на куски по 20 (или сколько-то) книг
|
||||
** сделать действия в меню (заполнение через NetworkTreeActions)
|
||||
|
|
|
@ -36,13 +36,17 @@ abstract class ItemsLoadingHandler extends Handler {
|
|||
private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>();
|
||||
private final Object myItemsMonitor = new Object();
|
||||
|
||||
private volatile boolean myFinishProcessed;
|
||||
private final Object myFinishMonitor = new Object();
|
||||
|
||||
|
||||
public final void addItem(NetworkLibraryItem item) {
|
||||
synchronized (myItemsMonitor) {
|
||||
myItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public final void ensureFinish() {
|
||||
public final void ensureItemsProcessed() {
|
||||
synchronized (myItemsMonitor) {
|
||||
while (myItems.size() > 0) {
|
||||
try {
|
||||
|
@ -53,27 +57,52 @@ abstract class ItemsLoadingHandler extends Handler {
|
|||
}
|
||||
}
|
||||
|
||||
public final void sendUpdateItems() {
|
||||
sendEmptyMessage(WHAT_UPDATE_ITEMS);
|
||||
}
|
||||
|
||||
public final void sendFinish(String errorMessage) {
|
||||
sendMessage(obtainMessage(WHAT_FINISHED, errorMessage));
|
||||
}
|
||||
|
||||
public abstract void onUpdateItems(List<NetworkLibraryItem> items);
|
||||
public abstract void afterUpdateItems();
|
||||
public abstract void onFinish(String errorMessage);
|
||||
|
||||
private final void doUpdateItems() {
|
||||
synchronized (myItemsMonitor) {
|
||||
onUpdateItems(myItems);
|
||||
myItems.clear();
|
||||
myItemsMonitor.notifyAll(); // wake up process, that waits for all items to be displayed (see ensureFinish() method)
|
||||
myItemsMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method)
|
||||
}
|
||||
afterUpdateItems();
|
||||
}
|
||||
|
||||
public final void ensureFinishProcessed() {
|
||||
synchronized (myFinishMonitor) {
|
||||
while (!myFinishProcessed) {
|
||||
try {
|
||||
myFinishMonitor.wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void doProcessFinish(String errorMessage, boolean interrupted) {
|
||||
synchronized (myFinishMonitor) {
|
||||
onFinish(errorMessage, interrupted);
|
||||
myFinishProcessed = true;
|
||||
myFinishMonitor.notifyAll(); // wake up process, that waits for finish condition (see ensureFinish() method)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sending messages methods
|
||||
public final void sendUpdateItems() {
|
||||
sendEmptyMessage(WHAT_UPDATE_ITEMS);
|
||||
}
|
||||
|
||||
public final void sendFinish(String errorMessage, boolean interrupted) {
|
||||
int arg1 = interrupted ? 1 : 0;
|
||||
sendMessage(obtainMessage(WHAT_FINISHED, arg1, 0, errorMessage));
|
||||
}
|
||||
|
||||
|
||||
// callbacks
|
||||
public abstract void onUpdateItems(List<NetworkLibraryItem> items);
|
||||
public abstract void afterUpdateItems();
|
||||
public abstract void onFinish(String errorMessage, boolean interrupted);
|
||||
|
||||
|
||||
@Override
|
||||
public final void handleMessage(Message message) {
|
||||
switch (message.what) {
|
||||
|
@ -81,7 +110,7 @@ abstract class ItemsLoadingHandler extends Handler {
|
|||
doUpdateItems();
|
||||
break;
|
||||
case WHAT_FINISHED:
|
||||
onFinish((String) message.obj);
|
||||
doProcessFinish((String) message.obj, message.arg1 != 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
package org.geometerplus.android.fbreader.network;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import android.os.Message;
|
||||
import android.os.Handler;
|
||||
|
||||
import org.geometerplus.fbreader.network.NetworkOperationData;
|
||||
import org.geometerplus.fbreader.network.NetworkLibraryItem;
|
||||
|
@ -30,7 +31,6 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
public static final int CATALOG_LOADING = 0;
|
||||
public static final int NETWORK_SEARCH = 1;
|
||||
|
||||
public final AtomicBoolean InterruptFlag = new AtomicBoolean();
|
||||
public final int Type;
|
||||
|
||||
private final ItemsLoadingHandler myHandler;
|
||||
|
@ -38,6 +38,47 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
private final long myUpdateInterval; // in milliseconds
|
||||
private final int myItemsLimit;
|
||||
|
||||
private boolean myInterruptRequested;
|
||||
private boolean myInterruptConfirmed;
|
||||
private Object myInterruptLock = new Object();
|
||||
|
||||
|
||||
private boolean myFinished;
|
||||
private Handler myFinishedHandler;
|
||||
private Object myFinishedLock = new Object();
|
||||
|
||||
|
||||
public void interrupt() {
|
||||
synchronized (myInterruptLock) {
|
||||
myInterruptRequested = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean confirmInterrupt() {
|
||||
synchronized (myInterruptLock) {
|
||||
if (myInterruptRequested) {
|
||||
myInterruptConfirmed = true;
|
||||
}
|
||||
return myInterruptConfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryResume() {
|
||||
synchronized (myInterruptLock) {
|
||||
if (!myInterruptConfirmed) {
|
||||
myInterruptRequested = false;
|
||||
}
|
||||
return !myInterruptRequested;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInterrupted() {
|
||||
synchronized (myInterruptLock) {
|
||||
return myInterruptConfirmed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ItemsLoadingRunnable(ItemsLoadingHandler handler, int type) {
|
||||
this(handler, type, 1000, 500);
|
||||
}
|
||||
|
@ -59,7 +100,7 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
public final void run() {
|
||||
String err = doBefore();
|
||||
if (err != null) {
|
||||
myHandler.sendFinish(err);
|
||||
myHandler.sendFinish(err, false);
|
||||
return;
|
||||
}
|
||||
err = doLoading(new NetworkOperationData.OnNewItemListener() {
|
||||
|
@ -67,7 +108,8 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
private int myItemsNumber;
|
||||
public boolean onNewItem(NetworkLibraryItem item) {
|
||||
myHandler.addItem(item);
|
||||
if (InterruptFlag.get() || myItemsNumber++ >= myItemsLimit) {
|
||||
final boolean interrupted = confirmInterrupt();
|
||||
if (interrupted || myItemsNumber++ >= myItemsLimit) {
|
||||
return true;
|
||||
}
|
||||
final long now = System.currentTimeMillis();
|
||||
|
@ -79,7 +121,31 @@ abstract class ItemsLoadingRunnable implements Runnable {
|
|||
}
|
||||
});
|
||||
myHandler.sendUpdateItems();
|
||||
myHandler.ensureFinish();
|
||||
myHandler.sendFinish(err);
|
||||
myHandler.ensureItemsProcessed();
|
||||
myHandler.sendFinish(err, isInterrupted());
|
||||
myHandler.ensureFinishProcessed();
|
||||
synchronized (myFinishedLock) {
|
||||
if (myFinishedHandler != null) {
|
||||
myFinishedHandler.sendEmptyMessage(0);
|
||||
}
|
||||
myFinished = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void runOnFinish(final Runnable runnable) {
|
||||
if (myFinishedHandler != null) {
|
||||
return;
|
||||
}
|
||||
synchronized (myFinishedLock) {
|
||||
if (myFinished) {
|
||||
runnable.run();
|
||||
} else {
|
||||
myFinishedHandler = new Handler() {
|
||||
public void handleMessage(Message message) {
|
||||
runnable.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
public static final int SIGNIN_ITEM_ID = 4;
|
||||
public static final int SIGNOUT_ITEM_ID = 5;
|
||||
public static final int REFILL_ACCOUNT_ITEM_ID = 6;
|
||||
public static final int STOP_LOADING_ITEM_ID = 7;
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -77,17 +76,17 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
|
||||
if (catalogUrl != null) {
|
||||
addMenuItem(menu, OPEN_CATALOG_ITEM_ID, "openCatalog");
|
||||
if (isLoading) {
|
||||
/*if (isLoading) {
|
||||
if (catalogRunnable.InterruptFlag.get()) {
|
||||
addMenuItem(menu, TREE_NO_ACTION, "stoppingCatalogLoading");
|
||||
} else {
|
||||
addMenuItem(menu, STOP_LOADING_ITEM_ID, "stopLoading");
|
||||
addMenuItem(menu, TREE_NO_ACTION, "stopLoading");
|
||||
}
|
||||
} else {
|
||||
if (catalogTree.hasChildren()) {
|
||||
addMenuItem(menu, RELOAD_ITEM_ID, "reload");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
if (tree instanceof NetworkCatalogRootTree) {
|
||||
|
@ -164,9 +163,6 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
((NetworkCatalogTree)tree).Item.Link.authenticationManager().refillAccountLink()
|
||||
);
|
||||
return true;
|
||||
case STOP_LOADING_ITEM_ID:
|
||||
doStopLoading((NetworkCatalogTree)tree);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -195,11 +191,16 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
}
|
||||
|
||||
public void onFinish(String errorMessage) {
|
||||
afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0);
|
||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
library.invalidateAccountDependents();
|
||||
library.synchronize();
|
||||
public void onFinish(String errorMessage, boolean interrupted) {
|
||||
if (interrupted) {
|
||||
myTree.ChildrenItems.clear();
|
||||
myTree.clear();
|
||||
} else {
|
||||
afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0);
|
||||
final NetworkLibrary library = NetworkLibrary.Instance();
|
||||
library.invalidateAccountDependents();
|
||||
library.synchronize();
|
||||
}
|
||||
if (NetworkView.Instance().isInitialized()) {
|
||||
NetworkView.Instance().fireModelChanged();
|
||||
}
|
||||
|
@ -279,23 +280,26 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
}
|
||||
}
|
||||
|
||||
public void doExpandCatalog(NetworkBaseActivity activity, final NetworkCatalogTree tree) {
|
||||
public void doExpandCatalog(final NetworkBaseActivity activity, final NetworkCatalogTree tree) {
|
||||
final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
if (url == null) {
|
||||
throw new RuntimeException("That's impossible!!!");
|
||||
}
|
||||
if (tree.hasChildren()
|
||||
|| NetworkView.Instance().containsItemsLoadingRunnable(url)) {
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
return;
|
||||
}
|
||||
final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, url);
|
||||
NetworkView.Instance().startItemsLoading(
|
||||
activity,
|
||||
url,
|
||||
new ExpandCatalogRunnable(handler, tree, true)
|
||||
);
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
NetworkView.Instance().tryResumeLoading(activity, tree, url, new Runnable() {
|
||||
public void run() {
|
||||
if (tree.hasChildren()) {
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
return;
|
||||
}
|
||||
final ExpandCatalogHandler handler = new ExpandCatalogHandler(tree, url);
|
||||
NetworkView.Instance().startItemsLoading(
|
||||
activity,
|
||||
url,
|
||||
new ExpandCatalogRunnable(handler, tree, true)
|
||||
);
|
||||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void doReloadCatalog(NetworkBaseActivity activity, final NetworkCatalogTree tree) {
|
||||
|
@ -318,17 +322,6 @@ class NetworkCatalogActions extends NetworkTreeActions {
|
|||
NetworkView.Instance().openTree(activity, tree, url);
|
||||
}
|
||||
|
||||
private void doStopLoading(NetworkCatalogTree tree) {
|
||||
final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
if (url == null) {
|
||||
throw new RuntimeException("That's impossible!!!");
|
||||
}
|
||||
final ItemsLoadingRunnable runnable = NetworkView.Instance().getItemsLoadingRunnable(url);
|
||||
if (runnable != null) {
|
||||
runnable.InterruptFlag.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void doSignOut(NetworkBaseActivity activity, NetworkCatalogTree tree) {
|
||||
final Handler handler = new Handler() {
|
||||
public void handleMessage(Message message) {
|
||||
|
|
|
@ -150,4 +150,30 @@ public class NetworkCatalogActivity extends NetworkBaseActivity {
|
|||
public void onModelChanged() {
|
||||
getListView().invalidateViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
|
||||
doStopLoading();
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
private void doStopLoading() {
|
||||
ItemsLoadingRunnable runnable = null;
|
||||
if (myTree instanceof NetworkCatalogTree) {
|
||||
final String url = ((NetworkCatalogTree) myTree).Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
|
||||
if (url == null) {
|
||||
throw new RuntimeException("That's impossible!!!");
|
||||
}
|
||||
runnable = NetworkView.Instance().getItemsLoadingRunnable(url);
|
||||
} else if (myTree instanceof SearchItemTree) {
|
||||
if (NetworkView.Instance().isInitialized()) {
|
||||
runnable = NetworkView.Instance().getItemsLoadingRunnable(NetworkSearchActivity.SEARCH_RUNNABLE_KEY);
|
||||
}
|
||||
}
|
||||
if (runnable != null) {
|
||||
runnable.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ import org.geometerplus.fbreader.network.*;
|
|||
class NetworkSearchActions extends NetworkTreeActions {
|
||||
|
||||
public static final int OPEN_RESULTS_ITEM_ID = 0;
|
||||
public static final int STOP_LOADING_ITEM_ID = 1;
|
||||
public static final int RUN_SEARCH_ITEM_ID = 2;
|
||||
|
||||
|
||||
|
@ -72,13 +71,13 @@ class NetworkSearchActions extends NetworkTreeActions {
|
|||
if (isLoading || tree.hasChildren()) {
|
||||
addMenuItem(menu, OPEN_RESULTS_ITEM_ID, "showResults");
|
||||
}
|
||||
if (isLoading) {
|
||||
/*if (isLoading) {
|
||||
if (searchRunnable.InterruptFlag.get()) {
|
||||
addMenuItem(menu, TREE_NO_ACTION, "stoppingNetworkSearch");
|
||||
} else {
|
||||
addMenuItem(menu, STOP_LOADING_ITEM_ID, "stopSearching");
|
||||
addMenuItem(menu, TREE_NO_ACTION, "stopSearching");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,9 +100,6 @@ class NetworkSearchActions extends NetworkTreeActions {
|
|||
case OPEN_RESULTS_ITEM_ID:
|
||||
doExpandCatalog(activity, (SearchItemTree)tree);
|
||||
return true;
|
||||
case STOP_LOADING_ITEM_ID:
|
||||
doStopLoading((SearchItemTree)tree);
|
||||
return true;
|
||||
case RUN_SEARCH_ITEM_ID:
|
||||
activity.onSearchRequested();
|
||||
return true;
|
||||
|
@ -112,20 +108,16 @@ class NetworkSearchActions extends NetworkTreeActions {
|
|||
}
|
||||
|
||||
|
||||
public void doExpandCatalog(NetworkBaseActivity activity, final SearchItemTree tree) {
|
||||
public void doExpandCatalog(final NetworkBaseActivity activity, final SearchItemTree tree) {
|
||||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return;
|
||||
}
|
||||
NetworkView.Instance().openTree(activity, tree, NetworkSearchActivity.SEARCH_RUNNABLE_KEY);
|
||||
}
|
||||
|
||||
private void doStopLoading(SearchItemTree tree) {
|
||||
if (!NetworkView.Instance().isInitialized()) {
|
||||
return;
|
||||
}
|
||||
final ItemsLoadingRunnable runnable = NetworkView.Instance().getItemsLoadingRunnable(NetworkSearchActivity.SEARCH_RUNNABLE_KEY);
|
||||
if (runnable != null) {
|
||||
runnable.InterruptFlag.set(true);
|
||||
}
|
||||
NetworkView.Instance().tryResumeLoading(activity, tree, NetworkSearchActivity.SEARCH_RUNNABLE_KEY, new Runnable() {
|
||||
public void run() {
|
||||
if (tree.hasChildren()) {
|
||||
NetworkView.Instance().openTree(activity, tree, NetworkSearchActivity.SEARCH_RUNNABLE_KEY);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,12 +81,16 @@ public class NetworkSearchActivity extends Activity {
|
|||
}
|
||||
}
|
||||
|
||||
public void onFinish(String errorMessage) {
|
||||
myTree.updateSubTrees();
|
||||
public void onFinish(String errorMessage, boolean interrupted) {
|
||||
if (interrupted) {
|
||||
myTree.setSearchResult(null);
|
||||
} else {
|
||||
myTree.updateSubTrees();
|
||||
afterUpdateCatalog(errorMessage, myTree.getSearchResult().empty());
|
||||
}
|
||||
if (NetworkView.Instance().isInitialized()) {
|
||||
NetworkView.Instance().fireModelChanged();
|
||||
}
|
||||
afterUpdateCatalog(errorMessage, myTree.getSearchResult().empty());
|
||||
}
|
||||
|
||||
private void afterUpdateCatalog(String errorMessage, boolean childrenEmpty) {
|
||||
|
|
|
@ -122,6 +122,18 @@ class NetworkView {
|
|||
return getItemsLoadingRunnable(key) != null;
|
||||
}
|
||||
|
||||
public void tryResumeLoading(NetworkBaseActivity activity, NetworkTree tree, String key, Runnable expandRunnable) {
|
||||
final ItemsLoadingRunnable runnable = NetworkView.Instance().getItemsLoadingRunnable(key);
|
||||
if (runnable != null && runnable.tryResume()) {
|
||||
openTree(activity, tree, key);
|
||||
return;
|
||||
}
|
||||
if (runnable == null) {
|
||||
expandRunnable.run();
|
||||
} else {
|
||||
runnable.runOnFinish(expandRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Loading covers
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue