1
0
Fork 0
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:
Vasiliy Bout 2010-05-11 16:39:35 +00:00
parent 377923f68b
commit 70901bcf3c
8 changed files with 203 additions and 81 deletions

View file

@ -16,8 +16,8 @@ DONE Network library: Объединять книги по сериям
NP: а где это происходит??? NP: а где это происходит???
** изменить вид библиотеки -- вместо дерева -- последовательные view без сдвига вправо (как в маркете) ** изменить вид библиотеки -- вместо дерева -- последовательные view без сдвига вправо (как в маркете)
DONE сделать пункт Search в дереве DONE сделать пункт Search в дереве
** при нажатии на кнопку 'Esc' -- возвращаться к предыдущему view + прерывать загрузку, если она еще идет; DONE при нажатии на кнопку 'Esc' -- возвращаться к предыдущему view + прерывать загрузку, если она еще идет;
** прерывание вручную умирает => загружать заново после прерывания DONE прерывание вручную умирает => загружать заново после прерывания
* соответственно, каталог должен иметь не 2 состояния -- загружен/не загружен, а загружен полностью/не полностью/не загружен; * соответственно, каталог должен иметь не 2 состояния -- загружен/не загружен, а загружен полностью/не полностью/не загружен;
в случае загрузки не полностью можно при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что подделены на куски по 20 (или сколько-то) книг в случае загрузки не полностью можно при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что подделены на куски по 20 (или сколько-то) книг
** сделать действия в меню (заполнение через NetworkTreeActions) ** сделать действия в меню (заполнение через NetworkTreeActions)

View file

@ -36,13 +36,17 @@ abstract class ItemsLoadingHandler extends Handler {
private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>(); private final LinkedList<NetworkLibraryItem> myItems = new LinkedList<NetworkLibraryItem>();
private final Object myItemsMonitor = new Object(); private final Object myItemsMonitor = new Object();
private volatile boolean myFinishProcessed;
private final Object myFinishMonitor = new Object();
public final void addItem(NetworkLibraryItem item) { public final void addItem(NetworkLibraryItem item) {
synchronized (myItemsMonitor) { synchronized (myItemsMonitor) {
myItems.add(item); myItems.add(item);
} }
} }
public final void ensureFinish() { public final void ensureItemsProcessed() {
synchronized (myItemsMonitor) { synchronized (myItemsMonitor) {
while (myItems.size() > 0) { while (myItems.size() > 0) {
try { 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() { private final void doUpdateItems() {
synchronized (myItemsMonitor) { synchronized (myItemsMonitor) {
onUpdateItems(myItems); onUpdateItems(myItems);
myItems.clear(); 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(); 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 @Override
public final void handleMessage(Message message) { public final void handleMessage(Message message) {
switch (message.what) { switch (message.what) {
@ -81,7 +110,7 @@ abstract class ItemsLoadingHandler extends Handler {
doUpdateItems(); doUpdateItems();
break; break;
case WHAT_FINISHED: case WHAT_FINISHED:
onFinish((String) message.obj); doProcessFinish((String) message.obj, message.arg1 != 0);
break; break;
} }
} }

View file

@ -19,7 +19,8 @@
package org.geometerplus.android.fbreader.network; 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.NetworkOperationData;
import org.geometerplus.fbreader.network.NetworkLibraryItem; 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 CATALOG_LOADING = 0;
public static final int NETWORK_SEARCH = 1; public static final int NETWORK_SEARCH = 1;
public final AtomicBoolean InterruptFlag = new AtomicBoolean();
public final int Type; public final int Type;
private final ItemsLoadingHandler myHandler; private final ItemsLoadingHandler myHandler;
@ -38,6 +38,47 @@ abstract class ItemsLoadingRunnable implements Runnable {
private final long myUpdateInterval; // in milliseconds private final long myUpdateInterval; // in milliseconds
private final int myItemsLimit; 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) { public ItemsLoadingRunnable(ItemsLoadingHandler handler, int type) {
this(handler, type, 1000, 500); this(handler, type, 1000, 500);
} }
@ -59,7 +100,7 @@ abstract class ItemsLoadingRunnable implements Runnable {
public final void run() { public final void run() {
String err = doBefore(); String err = doBefore();
if (err != null) { if (err != null) {
myHandler.sendFinish(err); myHandler.sendFinish(err, false);
return; return;
} }
err = doLoading(new NetworkOperationData.OnNewItemListener() { err = doLoading(new NetworkOperationData.OnNewItemListener() {
@ -67,7 +108,8 @@ abstract class ItemsLoadingRunnable implements Runnable {
private int myItemsNumber; private int myItemsNumber;
public boolean onNewItem(NetworkLibraryItem item) { public boolean onNewItem(NetworkLibraryItem item) {
myHandler.addItem(item); myHandler.addItem(item);
if (InterruptFlag.get() || myItemsNumber++ >= myItemsLimit) { final boolean interrupted = confirmInterrupt();
if (interrupted || myItemsNumber++ >= myItemsLimit) {
return true; return true;
} }
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
@ -79,7 +121,31 @@ abstract class ItemsLoadingRunnable implements Runnable {
} }
}); });
myHandler.sendUpdateItems(); myHandler.sendUpdateItems();
myHandler.ensureFinish(); myHandler.ensureItemsProcessed();
myHandler.sendFinish(err); 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();
}
};
}
}
} }
} }

View file

@ -48,7 +48,6 @@ class NetworkCatalogActions extends NetworkTreeActions {
public static final int SIGNIN_ITEM_ID = 4; public static final int SIGNIN_ITEM_ID = 4;
public static final int SIGNOUT_ITEM_ID = 5; public static final int SIGNOUT_ITEM_ID = 5;
public static final int REFILL_ACCOUNT_ITEM_ID = 6; public static final int REFILL_ACCOUNT_ITEM_ID = 6;
public static final int STOP_LOADING_ITEM_ID = 7;
@Override @Override
@ -77,17 +76,17 @@ class NetworkCatalogActions extends NetworkTreeActions {
if (catalogUrl != null) { if (catalogUrl != null) {
addMenuItem(menu, OPEN_CATALOG_ITEM_ID, "openCatalog"); addMenuItem(menu, OPEN_CATALOG_ITEM_ID, "openCatalog");
if (isLoading) { /*if (isLoading) {
if (catalogRunnable.InterruptFlag.get()) { if (catalogRunnable.InterruptFlag.get()) {
addMenuItem(menu, TREE_NO_ACTION, "stoppingCatalogLoading"); addMenuItem(menu, TREE_NO_ACTION, "stoppingCatalogLoading");
} else { } else {
addMenuItem(menu, STOP_LOADING_ITEM_ID, "stopLoading"); addMenuItem(menu, TREE_NO_ACTION, "stopLoading");
} }
} else { } else {
if (catalogTree.hasChildren()) { if (catalogTree.hasChildren()) {
addMenuItem(menu, RELOAD_ITEM_ID, "reload"); addMenuItem(menu, RELOAD_ITEM_ID, "reload");
} }
} }*/
} }
if (tree instanceof NetworkCatalogRootTree) { if (tree instanceof NetworkCatalogRootTree) {
@ -164,9 +163,6 @@ class NetworkCatalogActions extends NetworkTreeActions {
((NetworkCatalogTree)tree).Item.Link.authenticationManager().refillAccountLink() ((NetworkCatalogTree)tree).Item.Link.authenticationManager().refillAccountLink()
); );
return true; return true;
case STOP_LOADING_ITEM_ID:
doStopLoading((NetworkCatalogTree)tree);
return true;
} }
return false; return false;
} }
@ -195,11 +191,16 @@ class NetworkCatalogActions extends NetworkTreeActions {
} }
} }
public void onFinish(String errorMessage) { public void onFinish(String errorMessage, boolean interrupted) {
if (interrupted) {
myTree.ChildrenItems.clear();
myTree.clear();
} else {
afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0); afterUpdateCatalog(errorMessage, myTree.ChildrenItems.size() == 0);
final NetworkLibrary library = NetworkLibrary.Instance(); final NetworkLibrary library = NetworkLibrary.Instance();
library.invalidateAccountDependents(); library.invalidateAccountDependents();
library.synchronize(); library.synchronize();
}
if (NetworkView.Instance().isInitialized()) { if (NetworkView.Instance().isInitialized()) {
NetworkView.Instance().fireModelChanged(); NetworkView.Instance().fireModelChanged();
} }
@ -279,13 +280,14 @@ 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); final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
if (url == null) { if (url == null) {
throw new RuntimeException("That's impossible!!!"); throw new RuntimeException("That's impossible!!!");
} }
if (tree.hasChildren() NetworkView.Instance().tryResumeLoading(activity, tree, url, new Runnable() {
|| NetworkView.Instance().containsItemsLoadingRunnable(url)) { public void run() {
if (tree.hasChildren()) {
NetworkView.Instance().openTree(activity, tree, url); NetworkView.Instance().openTree(activity, tree, url);
return; return;
} }
@ -297,6 +299,8 @@ class NetworkCatalogActions extends NetworkTreeActions {
); );
NetworkView.Instance().openTree(activity, tree, url); NetworkView.Instance().openTree(activity, tree, url);
} }
});
}
public void doReloadCatalog(NetworkBaseActivity activity, final NetworkCatalogTree tree) { public void doReloadCatalog(NetworkBaseActivity activity, final NetworkCatalogTree tree) {
final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG); final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
@ -318,17 +322,6 @@ class NetworkCatalogActions extends NetworkTreeActions {
NetworkView.Instance().openTree(activity, tree, url); 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) { private void doSignOut(NetworkBaseActivity activity, NetworkCatalogTree tree) {
final Handler handler = new Handler() { final Handler handler = new Handler() {
public void handleMessage(Message message) { public void handleMessage(Message message) {

View file

@ -150,4 +150,30 @@ public class NetworkCatalogActivity extends NetworkBaseActivity {
public void onModelChanged() { public void onModelChanged() {
getListView().invalidateViews(); 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();
}
}
} }

View file

@ -39,7 +39,6 @@ import org.geometerplus.fbreader.network.*;
class NetworkSearchActions extends NetworkTreeActions { class NetworkSearchActions extends NetworkTreeActions {
public static final int OPEN_RESULTS_ITEM_ID = 0; 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; public static final int RUN_SEARCH_ITEM_ID = 2;
@ -72,13 +71,13 @@ class NetworkSearchActions extends NetworkTreeActions {
if (isLoading || tree.hasChildren()) { if (isLoading || tree.hasChildren()) {
addMenuItem(menu, OPEN_RESULTS_ITEM_ID, "showResults"); addMenuItem(menu, OPEN_RESULTS_ITEM_ID, "showResults");
} }
if (isLoading) { /*if (isLoading) {
if (searchRunnable.InterruptFlag.get()) { if (searchRunnable.InterruptFlag.get()) {
addMenuItem(menu, TREE_NO_ACTION, "stoppingNetworkSearch"); addMenuItem(menu, TREE_NO_ACTION, "stoppingNetworkSearch");
} else { } else {
addMenuItem(menu, STOP_LOADING_ITEM_ID, "stopSearching"); addMenuItem(menu, TREE_NO_ACTION, "stopSearching");
}
} }
}*/
} }
@Override @Override
@ -101,9 +100,6 @@ class NetworkSearchActions extends NetworkTreeActions {
case OPEN_RESULTS_ITEM_ID: case OPEN_RESULTS_ITEM_ID:
doExpandCatalog(activity, (SearchItemTree)tree); doExpandCatalog(activity, (SearchItemTree)tree);
return true; return true;
case STOP_LOADING_ITEM_ID:
doStopLoading((SearchItemTree)tree);
return true;
case RUN_SEARCH_ITEM_ID: case RUN_SEARCH_ITEM_ID:
activity.onSearchRequested(); activity.onSearchRequested();
return true; 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()) { if (!NetworkView.Instance().isInitialized()) {
return; return;
} }
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); 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);
} }
});
} }
} }

View file

@ -81,12 +81,16 @@ public class NetworkSearchActivity extends Activity {
} }
} }
public void onFinish(String errorMessage) { public void onFinish(String errorMessage, boolean interrupted) {
if (interrupted) {
myTree.setSearchResult(null);
} else {
myTree.updateSubTrees(); myTree.updateSubTrees();
afterUpdateCatalog(errorMessage, myTree.getSearchResult().empty());
}
if (NetworkView.Instance().isInitialized()) { if (NetworkView.Instance().isInitialized()) {
NetworkView.Instance().fireModelChanged(); NetworkView.Instance().fireModelChanged();
} }
afterUpdateCatalog(errorMessage, myTree.getSearchResult().empty());
} }
private void afterUpdateCatalog(String errorMessage, boolean childrenEmpty) { private void afterUpdateCatalog(String errorMessage, boolean childrenEmpty) {

View file

@ -122,6 +122,18 @@ class NetworkView {
return getItemsLoadingRunnable(key) != null; 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 covers