www.pudn.com > GMapViewer-src.zip > MapTileManager.java
package org.sreid.j2me.gmapviewer;
import java.util.*;
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import org.sreid.j2me.util.*;
class MapTileManager {
private final GMapViewer app;
private final MapTileCache cache;
MapTileManager(GMapViewer app) {
this.app = app;
cache = app.cache;
}
/**
* Requests a map tile. Returns from cache if possible. Begins loading if it's not already loaded.
*/
MapTile getMapTile(final XYZ xyz) {
MapTile mapTile1;
synchronized (cache) {
// Load cached, if possible.
mapTile1 = (MapTile)cache.get(xyz);
// If we found no tile, construct a new one.
if (mapTile1 == null) {
mapTile1 = new MapTile(xyz);
cache.put(mapTile1);
}
}
final MapTile mapTile = mapTile1; // final, so runnable below can use it
// Background download/decode.
final int requestID = app.canvas.requestID; // allows us to discard old requests
if (shouldDownloadTile(mapTile)) {
app.async1.enqueueJob(new Runnable() { public void run() {
if (app.canvas.requestID != requestID) return;
if (shouldDownloadTile(mapTile)) {
download(mapTile);
}
}});
}
else if (mapTile.image == null) {
app.async2.enqueueJob(new Runnable() { public void run() {
if (app.canvas.requestID != requestID) return;
if (mapTile.bytes == null) cache.loadFromRMS(mapTile);
decode(mapTile);
}});
}
return mapTile;
}
private boolean shouldDownloadTile(MapTile mt) {
return mt.bytes == null && mt.rmsID == -1 && !mt.downloading && app.online;
}
private void download(final MapTile mapTile) {
synchronized (mapTile) {
if (!shouldDownloadTile(mapTile)) {
return;
}
// Claim the task
mapTile.downloading = true;
}
app.canvas.repaint();
try {
byte[] buffer = (byte[])app.sharedBuffers.claimResourceIgnoreInterrupt();
try {
String params =
"&tx=" + mapTile.xyz.x +
"&ty=" + mapTile.xyz.y +
"&tz=" + mapTile.xyz.z ;
int count = app.getDataFromServer("maptile", params, buffer, "MAPTILE");
byte[] response = new byte[count];
System.arraycopy(buffer, 0, response, 0, count);
mapTile.bytes = response;
}
finally {
app.sharedBuffers.releaseResource(buffer);
}
cache.put(mapTile); // this is done after buffer released, as cache.put may need it
}
catch (Exception e) {
app.online = false;
app.exception("An error occured while downloading a map tile. Switching to offline mode.", e);
}
finally {
synchronized (mapTile) {
mapTile.downloading = false;
}
app.canvas.repaint();
}
}
private void decode(final MapTile mapTile) {
synchronized (mapTile) {
if (mapTile.image != null || mapTile.decoding || mapTile.bytes == null) {
// We don't need to / can't do anything.
return;
}
// Claim the task for ourselves.
mapTile.decoding = true;
}
try {
app.canvas.repaint(); // inform that decoding begins
mapTile.image = Image.createImage(mapTile.bytes, 0, mapTile.bytes.length);
cache.put(mapTile);
}
catch (Exception e) {
app.exception("An error occured while decoding a map tile image. This may be caused by memory fragmentation, which can only be fixed by restarting the program.", e);
cache.invalidate(mapTile); // force re-download of the tile (in case it really is a corrupt tile)
}
finally {
synchronized (mapTile) {
mapTile.decoding = false;
}
app.canvas.repaint(); // inform that decoding complete
}
}
}