From fbefe1ed3387ab7e09f8b8ab3e974193949aaa3d Mon Sep 17 00:00:00 2001 From: Florens Douwes Date: Sun, 9 Mar 2014 20:40:33 +0100 Subject: [PATCH] Now using a LoaderPool to obtain loaders. --- Chan/AndroidManifest.xml | 4 - .../floens/chan/activity/BoardActivity.java | 23 ++- .../floens/chan/activity/CatalogActivity.java | 106 ---------- .../org/floens/chan/adapter/PostAdapter.java | 4 +- .../floens/chan/fragment/ThreadFragment.java | 90 +++++---- .../chan/loader/EndOfLineException.java | 5 + Chan/src/org/floens/chan/loader/Loader.java | 155 +++++++++++++++ .../org/floens/chan/loader/LoaderPool.java | 47 +++++ .../org/floens/chan/loader/ThreadLoader.java | 124 ------------ .../floens/chan/manager/ThreadManager.java | 183 ++++++------------ Chan/src/org/floens/chan/model/Pin.java | 4 +- .../chan/view/ThreadWatchCounterView.java | 5 +- .../src/org/floens/chan/watch/PinWatcher.java | 10 +- 13 files changed, 336 insertions(+), 424 deletions(-) delete mode 100644 Chan/src/org/floens/chan/activity/CatalogActivity.java create mode 100644 Chan/src/org/floens/chan/loader/Loader.java create mode 100644 Chan/src/org/floens/chan/loader/LoaderPool.java delete mode 100644 Chan/src/org/floens/chan/loader/ThreadLoader.java diff --git a/Chan/AndroidManifest.xml b/Chan/AndroidManifest.xml index 39d9aa07..935eafa5 100644 --- a/Chan/AndroidManifest.xml +++ b/Chan/AndroidManifest.xml @@ -40,10 +40,6 @@ - - = getCount() - 1 && !endOfLine && threadManager.getLoadable().isBoardMode()) { // Try to load more posts - threadManager.loadMore(); + threadManager.requestNextData(); } if (position >= count) { @@ -80,7 +80,7 @@ public class PostAdapter extends BaseAdapter { } private View createThreadEndView() { - if (threadManager.getWatchLogic() != null) { + if (false/* && threadManager.getWatchLogic() != null*/) { ThreadWatchCounterView view = new ThreadWatchCounterView(context); Utils.setPressedDrawable(view); view.init(threadManager, listView, this); diff --git a/Chan/src/org/floens/chan/fragment/ThreadFragment.java b/Chan/src/org/floens/chan/fragment/ThreadFragment.java index 751c9858..5f7f323e 100644 --- a/Chan/src/org/floens/chan/fragment/ThreadFragment.java +++ b/Chan/src/org/floens/chan/fragment/ThreadFragment.java @@ -8,7 +8,6 @@ import org.floens.chan.adapter.PostAdapter; import org.floens.chan.imageview.activity.ImageViewActivity; import org.floens.chan.loader.EndOfLineException; import org.floens.chan.manager.ThreadManager; -import org.floens.chan.manager.ThreadManager.ThreadListener; import org.floens.chan.model.Loadable; import org.floens.chan.model.Post; import org.floens.chan.utils.LoadView; @@ -26,12 +25,12 @@ import android.widget.ListView; import com.android.volley.VolleyError; -public class ThreadFragment extends Fragment implements ThreadListener { +public class ThreadFragment extends Fragment implements ThreadManager.ThreadManagerListener { private BaseActivity baseActivity; private ThreadManager threadManager; - private PostAdapter postAdapter; - private boolean shown = false; private Loadable loadable; + + private PostAdapter postAdapter; private LoadView container; private ListView listView; @@ -43,8 +42,48 @@ public class ThreadFragment extends Fragment implements ThreadListener { return fragment; } - public ThreadManager getThreadManager() { - return threadManager; + public void bindLoadable(Loadable l) { + if (loadable != null) { + threadManager.unbindLoader(); + } + + setEmpty(); + + loadable = l; + threadManager.bindLoader(loadable); + } + + public void requestData() { + threadManager.requestData(); + } + + private void setEmpty() { + postAdapter = null; + + if (container != null) { + container.setView(null); + } + + if (listView != null) { + listView.setOnScrollListener(null); + listView = null; + } + } + + public void reload() { + setEmpty(); + + threadManager.requestData(); + } + + public void openReply() { + if (threadManager.hasLoader()) { + threadManager.openReply(true); + } + } + + public boolean hasLoader() { + return threadManager.hasLoader(); } @Override @@ -52,8 +91,6 @@ public class ThreadFragment extends Fragment implements ThreadListener { super.onDestroy(); if (threadManager != null) { - stopLoading(); - threadManager.onDestroy(); } } @@ -82,42 +119,9 @@ public class ThreadFragment extends Fragment implements ThreadListener { return container; } - public void stopLoading() { - if (threadManager != null) { - threadManager.stop(); - } - - shown = false; - postAdapter = null; - - if (container != null) { - container.setView(null); - } - - if (listView != null) { - listView.setOnScrollListener(null); - } - } - - public void startLoading(Loadable loadable) { - stopLoading(); - - this.loadable = loadable; - - threadManager.startLoading(loadable); - } - - public void reload() { - stopLoading(); - - threadManager.reload(); - } - @Override public void onThreadLoaded(List posts) { - if (!shown) { - shown = true; - + if (postAdapter == null) { listView = new ListView(baseActivity); postAdapter = new PostAdapter(baseActivity, threadManager, listView); @@ -166,7 +170,7 @@ public class ThreadFragment extends Fragment implements ThreadListener { } @Override - public void onPostClicked(Post post) { + public void onOPClicked(Post post) { baseActivity.onOPClicked(post); } diff --git a/Chan/src/org/floens/chan/loader/EndOfLineException.java b/Chan/src/org/floens/chan/loader/EndOfLineException.java index 6c2576de..c1087c40 100644 --- a/Chan/src/org/floens/chan/loader/EndOfLineException.java +++ b/Chan/src/org/floens/chan/loader/EndOfLineException.java @@ -12,4 +12,9 @@ public class EndOfLineException extends VolleyError { public EndOfLineException() { super(); } + + @Override + public String getMessage() { + return "End of the line"; + } } diff --git a/Chan/src/org/floens/chan/loader/Loader.java b/Chan/src/org/floens/chan/loader/Loader.java new file mode 100644 index 00000000..e945c6b2 --- /dev/null +++ b/Chan/src/org/floens/chan/loader/Loader.java @@ -0,0 +1,155 @@ +package org.floens.chan.loader; + +import java.util.ArrayList; +import java.util.List; + +import org.floens.chan.ChanApplication; +import org.floens.chan.model.Loadable; +import org.floens.chan.model.Post; +import org.floens.chan.utils.Logger; + +import android.util.SparseArray; + +import com.android.volley.Response; +import com.android.volley.ServerError; +import com.android.volley.VolleyError; + +public class Loader { + private static final String TAG = "Loader"; + + private final List listeners = new ArrayList(); + private final Loadable loadable; + private ChanReaderRequest request; + private boolean destroyed = false; + + private final SparseArray postsById = new SparseArray(); + + public Loader(Loadable loadable) { + this.loadable = loadable; + } + + /** + * Add a LoaderListener + * @param l the listener to add + */ + public void addListener(LoaderListener l) { + listeners.add(l); + } + + /** + * Remove a LoaderListener + * @param l the listener to remove + * @return true if there are no more listeners, false otherwise + */ + public boolean removeListener(LoaderListener l) { + listeners.remove(l); + if (listeners.size() == 0) { + destroyed = true; + return true; + } else { + return false; + } + } + + public void requestData() { + if (request != null) { + request.cancel(); + } + + postsById.clear(); + + if (loadable.isBoardMode()) { + loadable.no = 0; + loadable.listViewIndex = 0; + loadable.listViewTop = 0; + } + + request = getData(loadable); + } + + public void requestNextData() { + if (loadable.isBoardMode()) { + loadable.no++; + + if (request != null) { + request.cancel(); + } + + request = getData(loadable); + } + } + + /** + * @return Returns if this loader is currently loading + */ + public boolean isLoading() { + return request != null; + } + + public Post getPostById(int id) { + return postsById.get(id); + } + + public Loadable getLoadable() { + return loadable; + } + + private ChanReaderRequest getData(Loadable loadable) { + Logger.i(TAG, "Requested " + loadable.board + ", " + loadable.no); + + ChanReaderRequest request = ChanReaderRequest.newInstance(loadable, new Response.Listener>() { + @Override + public void onResponse(List list) { + Loader.this.request = null; + onData(list); + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + Loader.this.request = null; + onError(error); + } + }); + + ChanApplication.getVolleyRequestQueue().add(request); + + return request; + } + + private void onData(List result) { + if (destroyed) return; + + for (Post post : result) { + postsById.append(post.no, post); + } + + for (LoaderListener l : listeners) { + l.onData(result); + } + } + + private void onError(VolleyError error) { + if (destroyed) return; + + Logger.e(TAG, "Error loading " + error.getMessage(), error); + + // 404 with more pages already loaded means endofline + if ((error instanceof ServerError) && loadable.isBoardMode() && loadable.no > 0) { + error = new EndOfLineException(); + } + + for (LoaderListener l : listeners) { + l.onError(error); + } + } + + public static interface LoaderListener { + public void onData(List result); + public void onError(VolleyError error); + } +} + + + + + diff --git a/Chan/src/org/floens/chan/loader/LoaderPool.java b/Chan/src/org/floens/chan/loader/LoaderPool.java new file mode 100644 index 00000000..2cc8598b --- /dev/null +++ b/Chan/src/org/floens/chan/loader/LoaderPool.java @@ -0,0 +1,47 @@ +package org.floens.chan.loader; + +import java.util.HashMap; +import java.util.Map; + +import org.floens.chan.model.Loadable; +import org.floens.chan.utils.Logger; + +public class LoaderPool { + private static final String TAG = "LoaderPool"; + + private static LoaderPool instance; + + private static Map loaders = new HashMap(); + + public static LoaderPool getInstance() { + if (instance == null) { + instance = new LoaderPool(); + } + + return instance; + } + + public Loader obtain(Loadable loadable, Loader.LoaderListener listener) { + Logger.d(TAG, "loaders size: " + loaders.size()); + + Loader loader = loaders.get(loadable); + if (loader == null) { + loader = new Loader(loadable); + loaders.put(loadable, loader); + } + + loader.addListener(listener); + + return loader; + } + + public void release(Loader loader, Loader.LoaderListener listener) { + if (!loaders.containsValue(loader)) { + throw new RuntimeException("The released loader does not exist"); + } + + if (loader.removeListener(listener)) { + loaders.remove(loader); + } + } +} diff --git a/Chan/src/org/floens/chan/loader/ThreadLoader.java b/Chan/src/org/floens/chan/loader/ThreadLoader.java deleted file mode 100644 index 9a0631b5..00000000 --- a/Chan/src/org/floens/chan/loader/ThreadLoader.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.floens.chan.loader; - -import java.util.List; - -import org.floens.chan.ChanApplication; -import org.floens.chan.model.Loadable; -import org.floens.chan.model.Post; -import org.floens.chan.utils.Logger; - -import android.util.SparseArray; - -import com.android.volley.Response; -import com.android.volley.ServerError; -import com.android.volley.VolleyError; - -public class ThreadLoader { - private static final String TAG = "ThreadLoader"; - - private final ThreadLoaderListener listener; - private ChanReaderRequest loader; - private boolean stopped = false; - private boolean loading = false; - private Loadable loadable; - private final SparseArray postsById = new SparseArray(); - - public ThreadLoader(ThreadLoaderListener listener) { - this.listener = listener; - } - - /** - * @return Returns if this loader is currently loading - */ - public boolean isLoading() { - return loading; - } - - // public void start(int mode, String board, int pageOrThreadId) { - public void start(Loadable loadable) { - Logger.i(TAG, "Start loading " + loadable.board + ", " + loadable.no); - - stop(); - stopped = false; - - this.loadable = loadable; - loader = getData(loadable); - } - - public void loadMore() { - if (loadable.isBoardMode()) { - loadable.no++; - start(loadable); - } - } - - public void stop() { - if (loader != null) { -// Logger.i(TAG, "Stop loading"); - loader.cancel(); - loader = null; - } - - postsById.clear(); - - stopped = true; - } - - public Post getPostById(int id) { - return postsById.get(id); - } - - private ChanReaderRequest getData(Loadable loadable) { - ChanReaderRequest request = ChanReaderRequest.newInstance(loadable, new Response.Listener>() { - @Override - public void onResponse(List list) { - loading = false; - onData(list); - } - }, new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - loading = false; - onError(error); - } - }); - - ChanApplication.getVolleyRequestQueue().add(request); - loading = true; - - return request; - } - - private void onData(List result) { - if (stopped) return; - - for (Post post : result) { - postsById.append(post.no, post); - } - - listener.onData(result); - } - - private void onError(VolleyError error) { - if (stopped) return; - - Logger.e(TAG, "Error loading" + error.getMessage(), error); - - // 404 with more pages already loaded means endofline - if ((error instanceof ServerError) && loadable.isBoardMode() && loadable.no > 0) { - error = new EndOfLineException(); - } - - listener.onError(error); - } - - public static abstract interface ThreadLoaderListener { - public abstract void onData(List result); - public abstract void onError(VolleyError error); - } -} - - - - - diff --git a/Chan/src/org/floens/chan/manager/ThreadManager.java b/Chan/src/org/floens/chan/manager/ThreadManager.java index 4565814f..00de221d 100644 --- a/Chan/src/org/floens/chan/manager/ThreadManager.java +++ b/Chan/src/org/floens/chan/manager/ThreadManager.java @@ -8,18 +8,16 @@ import org.floens.chan.activity.ReplyActivity; import org.floens.chan.database.DatabaseManager; import org.floens.chan.fragment.PostRepliesFragment; import org.floens.chan.fragment.ReplyFragment; -import org.floens.chan.loader.ThreadLoader; +import org.floens.chan.loader.Loader; +import org.floens.chan.loader.LoaderPool; import org.floens.chan.manager.ReplyManager.DeleteListener; import org.floens.chan.manager.ReplyManager.DeleteResponse; import org.floens.chan.model.Loadable; -import org.floens.chan.model.Pin; import org.floens.chan.model.Post; import org.floens.chan.model.PostLinkable; import org.floens.chan.model.SavedReply; import org.floens.chan.utils.ChanPreferences; import org.floens.chan.utils.Logger; -import org.floens.chan.watch.WatchLogic; -import org.floens.chan.watch.WatchLogic.WatchListener; import android.app.Activity; import android.app.AlertDialog; @@ -50,165 +48,100 @@ import com.android.volley.VolleyError; * handling linkables, replies popups etc. * onDestroy, onPause and onResume must be called from the activity/fragment */ -public class ThreadManager implements ThreadLoader.ThreadLoaderListener, WatchListener { +public class ThreadManager implements Loader.LoaderListener { private static final String TAG = "ThreadManager"; private final Activity activity; - private final ThreadLoader threadLoader; - private final ThreadManager.ThreadListener threadListener; - private Loadable loadable; - private boolean endOfLine = false; - private WatchLogic watchLogic; - + private final ThreadManager.ThreadManagerListener threadManagerListener; private final List> popupQueue = new ArrayList>(); private PostRepliesFragment currentPopupFragment; - public ThreadManager(Activity context, final ThreadListener listener) { + private Loader loader; + + public ThreadManager(Activity context, final ThreadManagerListener listener) { this.activity = context; - threadListener = listener; - - threadLoader = new ThreadLoader(this); + threadManagerListener = listener; } public void onDestroy() { - if (watchLogic != null) { - watchLogic.destroy(); - watchLogic = null; - } + unbindLoader(); } public void onPause() { - if (watchLogic != null) { - watchLogic.stopTimer(); - } + } public void onResume() { - if (watchLogic != null) { - watchLogic.startTimer(); - } - } - - @Override - public void onWatchReloadRequested() { - Logger.d(TAG, "Reload requested"); - if (!threadLoader.isLoading()) { - threadLoader.start(loadable); - - Pin pin = PinnedManager.getInstance().findPinByLoadable(loadable); - if (pin != null) { - PinnedManager.getInstance().onPinViewed(pin); - } - } } - public WatchLogic getWatchLogic() { - return watchLogic; - } - - @Override - public void onError(VolleyError error) { - threadListener.onThreadLoadError(error); - - if (watchLogic != null) { - watchLogic.stopTimer(); + public void bindLoader(Loadable loadable) { + if (loader != null) { + unbindLoader(); } + + loader = LoaderPool.getInstance().obtain(loadable, this); } - @Override - public void onData(List result) { - if (watchLogic != null) { - watchLogic.onLoaded(result.size(), true); + public void unbindLoader() { + if (loader != null) { + LoaderPool.getInstance().release(loader, this); + loader = null; + } else { + Logger.e(TAG, "Loader already unbinded"); } - - threadListener.onThreadLoaded(result); } - public boolean hasLoadable() { - return loadable != null; + public void requestData() { + if (loader != null) { + loader.requestData(); + } else { + Logger.e(TAG, "Loader null in requestData"); + } } - public Post findPostById(int id) { - return threadLoader.getPostById(id); + /** + * Called by postadapter and threadwatchcounterview.onclick + */ + public void requestNextData() { + if (loader != null) { + loader.requestNextData(); + } else { + Logger.e(TAG, "Loader null in requestData"); + } } - public Loadable getLoadable() { - return loadable; + @Override + public void onError(VolleyError error) { + threadManagerListener.onThreadLoadError(error); } - public void startLoading(Loadable loadable) { - this.loadable = loadable; - - stop(); - - threadLoader.start(loadable); - - Pin pin = PinnedManager.getInstance().findPinByLoadable(loadable); - if (pin != null) { - PinnedManager.getInstance().onPinViewed(pin); - } - - if (watchLogic != null) { - watchLogic.destroy(); - watchLogic = null; - } - - if (loadable.isThreadMode()) { - watchLogic = new WatchLogic(this); - watchLogic.startTimer(); - } + @Override + public void onData(List result) { + threadManagerListener.onThreadLoaded(result); } - public void stop() { - threadLoader.stop(); - endOfLine = false; - - if (watchLogic != null) { - watchLogic.destroy(); - watchLogic = null; - } + public boolean hasLoader() { + return loader != null; } - public void reload() { - if (loadable == null) { - Logger.e(TAG, "ThreadManager: loadable null"); - } else { - if (loadable.isBoardMode()) { - loadable.no = 0; - loadable.listViewIndex = 0; - loadable.listViewTop = 0; - } - - startLoading(loadable); - } + public Post findPostById(int id) { + if (loader == null) return null; + return loader.getPostById(id); } - public void loadMore() { - if (threadLoader.isLoading()) return; - - if (loadable == null) { - Logger.e(TAG, "ThreadManager: loadable null"); - } else { - if (loadable.isBoardMode()) { - if (!endOfLine) { - threadLoader.loadMore(); - } - } else if (loadable.isThreadMode()) { - if (watchLogic != null) { - watchLogic.loadNow(); - } - } - } + public Loadable getLoadable() { + if (loader == null) return null; + return loader.getLoadable(); } public void onThumbnailClicked(Post post) { - threadListener.onThumbnailClicked(post); + threadManagerListener.onThumbnailClicked(post); } public void onPostClicked(Post post) { - if (loadable.isBoardMode()) { - threadListener.onPostClicked(post); + if (loader != null && loader.getLoadable().isBoardMode()) { + threadManagerListener.onOPClicked(post); } } @@ -257,12 +190,14 @@ public class ThreadManager implements ThreadLoader.ThreadLoaderListener, WatchLi } public void openReply(boolean startInActivity) { + if (loader == null) return; + if (startInActivity) { - ReplyActivity.setLoadable(loadable); + ReplyActivity.setLoadable(loader.getLoadable()); Intent i = new Intent(activity, ReplyActivity.class); activity.startActivity(i); } else { - ReplyFragment reply = ReplyFragment.newInstance(loadable); + ReplyFragment reply = ReplyFragment.newInstance(loader.getLoadable()); reply.show(activity.getFragmentManager(), "replyDialog"); } } @@ -562,10 +497,10 @@ public class ThreadManager implements ThreadLoader.ThreadLoaderListener, WatchLi }); } - public interface ThreadListener { + public interface ThreadManagerListener { public void onThreadLoaded(List result); public void onThreadLoadError(VolleyError error); - public void onPostClicked(Post post); + public void onOPClicked(Post post); public void onThumbnailClicked(Post post); } } diff --git a/Chan/src/org/floens/chan/model/Pin.java b/Chan/src/org/floens/chan/model/Pin.java index d38ea88b..c9257ce2 100644 --- a/Chan/src/org/floens/chan/model/Pin.java +++ b/Chan/src/org/floens/chan/model/Pin.java @@ -33,10 +33,10 @@ public class Pin { public void updateWatch() { if (pinWatcher == null) { - pinWatcher = new PinWatcher(this); +// pinWatcher = new PinWatcher(this); } - pinWatcher.update(); +// pinWatcher.update(); } } diff --git a/Chan/src/org/floens/chan/view/ThreadWatchCounterView.java b/Chan/src/org/floens/chan/view/ThreadWatchCounterView.java index 16a8d8e3..af886bda 100644 --- a/Chan/src/org/floens/chan/view/ThreadWatchCounterView.java +++ b/Chan/src/org/floens/chan/view/ThreadWatchCounterView.java @@ -57,12 +57,13 @@ public class ThreadWatchCounterView extends TextView implements View.OnClickList @Override public void onClick(View v) { - tm.loadMore(); + tm.requestNextData(); ad.notifyDataSetChanged(); } private void updateCounterText(ThreadManager threadManager) { - WatchLogic logic = threadManager.getWatchLogic(); +// WatchLogic logic = threadManager.getWatchLogic(); + WatchLogic logic = null; if (logic != null) { int time = Math.round(logic.timeLeft() / 1000f); diff --git a/Chan/src/org/floens/chan/watch/PinWatcher.java b/Chan/src/org/floens/chan/watch/PinWatcher.java index 6396b428..2fefa2c7 100644 --- a/Chan/src/org/floens/chan/watch/PinWatcher.java +++ b/Chan/src/org/floens/chan/watch/PinWatcher.java @@ -2,7 +2,7 @@ package org.floens.chan.watch; import java.util.List; -import org.floens.chan.loader.ThreadLoader; +import org.floens.chan.loader.Loader; import org.floens.chan.model.Loadable; import org.floens.chan.model.Pin; import org.floens.chan.model.Post; @@ -11,12 +11,12 @@ import org.floens.chan.utils.Logger; import com.android.volley.VolleyError; -public class PinWatcher implements ThreadLoader.ThreadLoaderListener { +public class PinWatcher implements Loader.LoaderListener { private static final String TAG = "PinWatcher"; private final Pin pin; private final Loadable loadable; - private final ThreadLoader loader; + private Loader loader; private final WatchLogic watchLogic; private long startTime; @@ -27,7 +27,7 @@ public class PinWatcher implements ThreadLoader.ThreadLoaderListener { loadable = pin.loadable.copy(); loadable.simpleMode = true; - loader = new ThreadLoader(this); +// loader = new Loader(this); watchLogic = new WatchLogic(); } @@ -38,7 +38,7 @@ public class PinWatcher implements ThreadLoader.ThreadLoaderListener { startTime = System.currentTimeMillis(); - loader.start(loadable); + loader.requestData(); } }