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: а где это происходит???
** изменить вид библиотеки -- вместо дерева -- последовательные view без сдвига вправо (как в маркете)
DONE сделать пункт Search в дереве
** при нажатии на кнопку 'Esc' -- возвращаться к предыдущему view + прерывать загрузку, если она еще идет;
** прерывание вручную умирает => загружать заново после прерывания
DONE при нажатии на кнопку 'Esc' -- возвращаться к предыдущему view + прерывать загрузку, если она еще идет;
DONE прерывание вручную умирает => загружать заново после прерывания
* соответственно, каталог должен иметь не 2 состояния -- загружен/не загружен, а загружен полностью/не полностью/не загружен;
в случае загрузки не полностью можно при повторном открытии продолжать загрузку с точки, где прервались (для тех каталогов, что подделены на куски по 20 (или сколько-то) книг
** сделать действия в меню (заполнение через NetworkTreeActions)

View file

@ -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;
}
}

View file

@ -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();
}
};
}
}
}
}

View file

@ -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) {
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,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);
if (url == null) {
throw new RuntimeException("That's impossible!!!");
}
if (tree.hasChildren()
|| NetworkView.Instance().containsItemsLoadingRunnable(url)) {
NetworkView.Instance().tryResumeLoading(activity, tree, url, new Runnable() {
public void run() {
if (tree.hasChildren()) {
NetworkView.Instance().openTree(activity, tree, url);
return;
}
@ -297,6 +299,8 @@ class NetworkCatalogActions extends NetworkTreeActions {
);
NetworkView.Instance().openTree(activity, tree, url);
}
});
}
public void doReloadCatalog(NetworkBaseActivity activity, final NetworkCatalogTree tree) {
final String url = tree.Item.URLByType.get(NetworkCatalogItem.URL_CATALOG);
@ -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) {

View file

@ -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();
}
}
}

View file

@ -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().tryResumeLoading(activity, tree, NetworkSearchActivity.SEARCH_RUNNABLE_KEY, new Runnable() {
public void run() {
if (tree.hasChildren()) {
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();
afterUpdateCatalog(errorMessage, myTree.getSearchResult().empty());
}
if (NetworkView.Instance().isInitialized()) {
NetworkView.Instance().fireModelChanged();
}
afterUpdateCatalog(errorMessage, myTree.getSearchResult().empty());
}
private void afterUpdateCatalog(String errorMessage, boolean childrenEmpty) {

View file

@ -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