package amidst.map; import java.util.Collections; import java.util.Stack; import java.util.concurrent.ConcurrentLinkedQueue; import amidst.logging.Log; public class FragmentManager implements Runnable { private int cacheSize = 1024; private Thread currentThread; private boolean running = true; private Fragment[] fragmentCache; private ConcurrentLinkedQueue<Fragment> fragmentQueue; private ConcurrentLinkedQueue<Fragment> requestQueue; private ConcurrentLinkedQueue<Fragment> recycleQueue; private int sleepTick = 0; private Object queueLock = new Object(); private Stack<ImageLayer> layerList; private ImageLayer[] imageLayers; private IconLayer[] iconLayers; private LiveLayer[] liveLayers; public FragmentManager(ImageLayer[] imageLayers, LiveLayer[] liveLayers, IconLayer[] iconLayers) { fragmentQueue = new ConcurrentLinkedQueue<Fragment>(); requestQueue = new ConcurrentLinkedQueue<Fragment>(); recycleQueue = new ConcurrentLinkedQueue<Fragment>(); layerList = new Stack<ImageLayer>(); Collections.addAll(layerList, imageLayers); fragmentCache = new Fragment[cacheSize]; for (int i = 0; i < imageLayers.length; i++) imageLayers[i].setLayerId(i); for (int i = 0; i < cacheSize; i++) { fragmentCache[i] = new Fragment(imageLayers, liveLayers, iconLayers); fragmentQueue.offer(fragmentCache[i]); } this.imageLayers = imageLayers; this.iconLayers = iconLayers; this.liveLayers = liveLayers; } public void updateLayers(float time) { for (ImageLayer layer : imageLayers) layer.update(time); for (LiveLayer layer : liveLayers) layer.update(time); for (IconLayer layer : iconLayers) layer.update(time); } public void reset() { running = false; try { currentThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } recycleQueue.clear(); requestQueue.clear(); fragmentQueue.clear(); for (int i = 0; i < cacheSize; i++) { fragmentCache[i].reset(); fragmentQueue.offer(fragmentCache[i]); } } private void increaseFragmentCache() { Fragment[] newFragments = new Fragment[cacheSize << 1]; for (int i = 0; i < cacheSize; i++) { newFragments[i] = fragmentCache[i]; fragmentCache[i] = null; } for (int i = cacheSize; i < cacheSize << 1; i++) { newFragments[i] = new Fragment(imageLayers, liveLayers, iconLayers); fragmentQueue.offer(newFragments[i]); } fragmentCache = newFragments; Log.i("FragmentManager cache size increased from " + cacheSize + " to " + (cacheSize << 1)); cacheSize <<= 1; System.gc(); } public void repaintFragment(Fragment frag) { synchronized (queueLock) { frag.repaint(); } } public Fragment requestFragment(int x, int y) { if (!running) return null; Fragment frag = null; while ((frag = fragmentQueue.poll()) == null) increaseFragmentCache(); frag.clear(); frag.blockX = x; frag.blockY = y; frag.isActive = true; requestQueue.offer(frag); return frag; } public void returnFragment(Fragment frag) { recycleQueue.offer(frag); } @Override public void run() { currentThread.setPriority(Thread.MIN_PRIORITY); while (running) { if(!requestQueue.isEmpty() || !recycleQueue.isEmpty()) { if (!requestQueue.isEmpty()) { synchronized (queueLock) { Fragment frag = requestQueue.poll(); if (frag.isActive && !frag.isLoaded) { frag.load(); sleepTick++; if (sleepTick == 10) { sleepTick = 0; try { Thread.sleep(1L); } catch (InterruptedException ignored) {} } } } } while (!recycleQueue.isEmpty()) { synchronized (queueLock) { Fragment frag = recycleQueue.poll(); frag.recycle(); fragmentQueue.offer(frag); } } } else { sleepTick = 0; try { Thread.sleep(2L); } catch (InterruptedException ignored) {} } } } public void setMap(Map map) { for (ImageLayer layer : imageLayers) { layer.setMap(map); layer.reload(); } for (LiveLayer layer : liveLayers) { layer.setMap(map); layer.reload(); } for (IconLayer layer : iconLayers) { layer.setMap(map); layer.reload(); } currentThread = new Thread(this); running = true; currentThread.start(); } public int getCacheSize() { return cacheSize; } public int getFreeFragmentQueueSize() { return fragmentQueue.size(); } public int getRecycleQueueSize() { return recycleQueue.size(); } public int getRequestQueueSize() { return requestQueue.size(); } public void repaintFragmentLayer(Fragment frag, int id) { synchronized (queueLock) { frag.repaintImageLayer(id); } } }