borrow AsyncTask stuff from libgdx

- for html backend async tasks are just put on Queue and run on next main-loop iteration
This commit is contained in:
Hannes Janetzek 2013-07-26 23:35:05 +02:00
parent 8787ac7b48
commit 5b16f6b085
11 changed files with 422 additions and 26 deletions

View File

@ -28,6 +28,7 @@ import org.oscim.view.MapView;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.RelativeLayout;
/**
@ -138,7 +139,7 @@ public class AndroidMapView extends RelativeLayout {
if (!mWaitRedraw) {
mWaitRedraw = true;
post(mRedrawRequest);
getView().post(mRedrawRequest);
}
}
@ -165,8 +166,13 @@ public class AndroidMapView extends RelativeLayout {
}
@Override
public boolean postRunnable(Runnable runnable) {
return post(runnable);
public boolean post(Runnable runnable) {
return getView().post(runnable);
}
@Override
public boolean postDelayed(Runnable action, long delay) {
return getView().postDelayed(action, delay);
}
};
@ -185,6 +191,9 @@ public class AndroidMapView extends RelativeLayout {
mMapView.updateMap(false);
}
View getView(){
return this;
}
public MapView getMap() {
return mMapView;

View File

@ -0,0 +1,60 @@
package org.oscim.utils.async;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.Timer;
/**
* GWT emulation of AsynchExecutor, will call tasks immediately :D
* @author badlogic
*
*/
public class AsyncExecutor implements Disposable {
/**
* Creates a new AsynchExecutor that allows maxConcurrent
* {@link Runnable} instances to run in parallel.
* @param maxConcurrent
*/
public AsyncExecutor(int maxConcurrent) {
}
// FIXME TODO add wrap into 'FakeFuture' and run via Gdx.app.post()
/**
* Submits a {@link Runnable} to be executed asynchronously. If
* maxConcurrent runnables are already running, the runnable
* will be queued.
* @param task the task to execute asynchronously
*/
@SuppressWarnings("rawtypes")
public <T> AsyncResult<T> submit(final AsyncTask<T> task) {
T result = null;
boolean error = false;
try {
task.run();
result = task.getResult();
} catch(Throwable t) {
error = true;
}
return new AsyncResult(result);
}
/**
* Submits a {@link Runnable} to be executed asynchronously. If
* maxConcurrent runnables are already running, the runnable
* will be queued.
* @param task the task to execute asynchronously
*/
public void post(Runnable task) {
Gdx.app.postRunnable(task);
}
/**
* Waits for running {@link AsyncTask} instances to finish,
* then destroys any resources like threads. Can not be used
* after this method is called.
*/
@Override
public void dispose () {
}
}

View File

@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright 2013 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils.async;
//import java.util.concurrent.ExecutionException;
//import java.util.concurrent.Future;
/**
* Returned by {@link AsyncExecutor#submit(AsyncTask)}, allows to poll
* for the result of the asynch workload.
* @author badlogic
*
*/
public class AsyncResult<T> {
private final T result;
AsyncResult(T result) {
this.result = result;
}
/**
* @return whether the {@link AsyncTask} is done
*/
public boolean isDone() {
return true;
}
/**
* @return the result, or null if there was an error, no result, or the task is still running
*/
public T get() {
return result;
}
}

View File

@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright 2013 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils.async;
/**
* Task to be submitted to an {@link AsyncExecutor}, returning a result of type T.
* @author badlogic
*
*/
public interface AsyncTask<T> extends Runnable{
public boolean cancel();
public T getResult() throws Exception;
}

View File

@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright 2013 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils.async;
/**
* GWT emulation of ThreadUtils, does nothing.
* @author badlogic
*
*/
public class ThreadUtils {
public static void yield() {
}
}

View File

@ -24,6 +24,8 @@ import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.input.GestureDetector.GestureListener;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.Timer.Task;
public class GdxMap implements ApplicationListener {
@ -66,13 +68,24 @@ public class GdxMap implements ApplicationListener {
}
@Override
public boolean postRunnable(Runnable runnable) {
public boolean post(Runnable runnable) {
Gdx.app.postRunnable(runnable);
return true;
}
@Override
public boolean postDelayed(final Runnable action, long delay) {
Timer.schedule(new Task(){
@Override
public void run() {
action.run();
}}, delay / 1000f);
return true;
}
};
mMapRenderer = new GLRenderer(mMapView);
}
// Stage ui;

View File

@ -0,0 +1,94 @@
/*******************************************************************************
* Copyright 2013 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils.async;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* Allows asnynchronous execution of {@link AsyncTask} instances on a separate thread.
* Needs to be disposed via a call to {@link #dispose()} when no longer used, in which
* case the executor waits for running tasks to finish. Scheduled but not yet
* running tasks will not be executed.
* @author badlogic
*
*/
public class AsyncExecutor {
private final ExecutorService executor;
/**
* Creates a new AsynchExecutor that allows maxConcurrent
* {@link Runnable} instances to run in parallel.
* @param maxConcurrent
*/
public AsyncExecutor(int maxConcurrent) {
executor = Executors.newFixedThreadPool(maxConcurrent, new ThreadFactory() {
@Override
public Thread newThread (Runnable r) {
Thread thread = new Thread(r, "VtmAsyncExecutor");
thread.setDaemon(true);
return thread;
}
});
}
/**
* Submits a {@link Runnable} to be executed asynchronously. If
* maxConcurrent runnables are already running, the runnable
* will be queued.
* @param task the task to execute asynchronously
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public <T> AsyncResult<T> submit(final AsyncTask<T> task) {
return new AsyncResult(executor.submit(new Callable<T>() {
@Override
public T call () throws Exception {
task.run();
return task.getResult();
}
}));
}
/**
* Submits a {@link Runnable} to be executed asynchronously. If
* maxConcurrent runnables are already running, the runnable
* will be queued.
* @param task the task to execute asynchronously
*/
public void post(Runnable task) {
executor.execute(task);
}
/**
* Waits for running {@link AsyncTask} instances to finish,
* then destroys any resources like threads. Can not be used
* after this method is called.
*/
//@Override
public void dispose () {
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
new RuntimeException("Couldn't shutdown loading thread");
}
}
}

View File

@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright 2013 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils.async;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/** Returned by {@link AsyncExecutor#submit(AsyncTask)}, allows to poll for the result of the asynch workload.
* @author badlogic */
public class AsyncResult<T> {
private final Future<T> future;
AsyncResult (Future<T> future) {
this.future = future;
}
/** @return whether the {@link AsyncTask} is done */
public boolean isDone () {
return future.isDone();
}
/** @return waits if necessary for the computation to complete and then returns the result
* @throws GdxRuntimeException if there was an error */
public T get () {
try {
return future.get();
} catch (InterruptedException ex) {
return null;
} catch (ExecutionException ex) {
throw new RuntimeException(ex.getCause());
}
}
}

View File

@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright 2013 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils.async;
/**
* Task to be submitted to an {@link AsyncExecutor}, returning a result of type T.
* @author badlogic
*
*/
public interface AsyncTask<T> extends Runnable{
public boolean cancel();
public T getResult() throws Exception;
}

View File

@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright 2013 See libgdx AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.oscim.utils.async;
/**
* Utilities for threaded programming.
*
* @author badlogic
*/
public class ThreadUtils {
public static void yield() {
Thread.yield();
}
}

View File

@ -31,6 +31,8 @@ import org.oscim.theme.IRenderTheme;
import org.oscim.theme.InternalRenderTheme;
import org.oscim.theme.ThemeLoader;
import org.oscim.tilesource.TileSource;
import org.oscim.utils.async.AsyncExecutor;
import org.oscim.utils.async.AsyncTask;
public abstract class MapView {
@ -40,35 +42,35 @@ public abstract class MapView {
private final LayerManager mLayerManager;
private final MapViewPosition mMapViewPosition;
private final MapPosition mMapPosition;
private final AsyncExecutor mAsyncExecutor;
private DebugSettings mDebugSettings;
protected boolean mClearMap;
public MapView() {
mMapViewPosition = new MapViewPosition(this);
mMapPosition = new MapPosition();
mLayerManager = new LayerManager();
mAsyncExecutor = new AsyncExecutor(2);
// FIXME
// FIXME!
mDebugSettings = new DebugSettings();
MapTileLoader.setDebugSettings(mDebugSettings);
mLayerManager.add(0, new MapEventLayer(this));
}
private MapTileLayer mBaseLayer;
//private BitmapTileLayer mBackgroundLayer;
public MapTileLayer setBaseMap(TileSource tileSource) {
mBaseLayer = new MapTileLayer(this);
mBaseLayer.setTileSource(tileSource);
//mLayerManager.add(0, new MapEventLayer(this));
mLayerManager.add(1, mBaseLayer);
//mRotationEnabled = true;
//mLayerManager.add(new GenericOverlay(this, new GridRenderLayer(this)));
return mBaseLayer;
}
@ -77,19 +79,18 @@ public abstract class MapView {
}
public MapTileLayer setBaseMap(BitmapTileLayer tileLayer) {
//mLayerManager.add(0, new MapEventLayer(this));
mLayerManager.add(1, tileLayer);
return null;
}
public void setTheme(InternalRenderTheme theme) {
if (mBaseLayer == null){
if (mBaseLayer == null) {
Log.e(TAG, "No base layer set");
throw new IllegalStateException();
}
IRenderTheme t = ThemeLoader.load(theme);
if (t == null){
if (t == null) {
Log.e(TAG, "Invalid theme");
throw new IllegalStateException();
}
@ -99,6 +100,7 @@ public abstract class MapView {
public void destroy() {
mLayerManager.destroy();
mAsyncExecutor.dispose();
}
/**
@ -110,12 +112,35 @@ public abstract class MapView {
*/
public abstract void updateMap(boolean forceRedraw);
/**
* Request to render a frame. Request will be handled on main
* thread. Use this for animations in RenderLayers.
*/
public abstract void render();
/**
* Post a runnable to be executed on main-thread
*/
public abstract boolean post(Runnable action);
/**
* Post a runnable to be executed on main-thread. Execution is delayed for
* at least 'delay' milliseconds.
*/
public abstract boolean postDelayed(Runnable action, long delay);
/**
* Post a task to run on a shared worker-thread. Only use for
* tasks running less than a second!
* */
public void addTask(Runnable task){
mAsyncExecutor.post(task);
}
public abstract int getWidth();
public abstract int getHeight();
public abstract boolean postRunnable(Runnable runnable);
protected boolean mClearMap;
public abstract int getHeight();
/**
* Request to clear all layers before rendering next frame
@ -124,12 +149,6 @@ public abstract class MapView {
mClearMap = true;
}
/**
* Request to render a frame. Request will be handled on main
* thread. Use this for animations.
*/
public abstract void render();
/**
* Do not call directly! This function is run on main-loop
* before rendering a frame.
@ -198,7 +217,4 @@ public abstract class MapView {
return mMapViewPosition.getViewBox();
}
}