So I have a loop class that is basically as follows:
public class Loop extends Thread {
private boolean running;
public Loop() {
running = false;
}
public void run() {
while(running) {
//Do stuff
}
}
public void setRunning(boolean b) {
running = b;
}
}
What I'd like to know is whether or not it is possible to store methods. For example the class could look like this instead.
public class Loop extends Thread {
private boolean running;
private Method method;
public Loop() {
running = false;
}
public void run() {
while(running) {
if(method != null)
method.callMethod();
}
}
public void setRunning(boolean b) {
running = b;
}
public void setMethod(Method m) {
method = m;
}
}
Is anything like this possible?
I assume you want this functionality in Java 6, so you can use interface and anonymous class.
Interface code:
public interface Listener {
void callMethod();
}
Your Thread:
public class Loop extends Thread {
private boolean running;
private Listener listener;
public Loop() {
running = false;
}
public void run() {
while(running) {
if(listener != null)
listener.callMethod();
}
}
public void setRunning(boolean b) {
running = b;
}
public void setListener(Listener listener) {
this.listener = listener;
}
}
Set Listener:
Loop loop = new Loop();
loop.setListener(new Listener() {
#Override
public void callMethod() {
// Do stuff
}
});
This will work for your usecase. If you want to save methods and pass methods as data, you have to either use Java 8 (not supported on all Android API levels) or Kotlin.
Related
I want to create efficienty timer in LibGDX framework, that will count the time left for my character. The doSmth() method should be called as many times as some flag is set to true. I know that the third parametr of Timer is that, how many times should it trigger. For now one Im calling the method recursive, but I dont think it is the efficient way.
public void updateTimer(){
new Timer().scheduleTask(new Timer.Task() {
#Override
public void run() {
doSmth();
updateTimer();
}
},1);
}
It would be more accurate to use a repeat count. Your method will introduce a bit of error each time the task is run, because the task is run on the GL thread, so it will occur just slightly after one second, but you are repeating it one second after that. So with each repeat you are slightly further behind.
private Timer.Task myTimerTask = new Timer.Task() {
#Override
public void run() {
doSmth();
}
};
public void startTimer(){
Timer.schedule(myTimerTask, 1f, 1f);
}
And when you need to stop it:
myTimerTask.cancel();
The com.badlogic.gdx.utils.Timer executes tasks in the future on the main loop thread,even if your game is in a pause screen, a menu or in another state, you can simply control time in the render method by adding delta time.
private float timeSeconds = 0f;
private float period = 1f;
public void render() {
//Execute handleEvent each 1 second
timeSeconds +=Gdx.graphics.getRawDeltaTime();
if(timeSeconds > period){
timeSeconds-=period;
handleEvent();
}
[...]
}
public void handleEvent() {
[...]
}
To keep organized i personally have an array on my main game class that holds all my timed events and process everything on the render cycle. In your case you can put some control variables as you wish.
my implementation example:
// MainGame.java
private ObjectMap<TimedEventEnum, TimedEvent> hshTimedEvent;
public void render(){
executeTimedEvents();
}
private void executeTimedEvents() {
for (ObjectMap.Entry<TimedEventEnum, TimedEvent> entry : hshTimedEvent) {
TimedEvent event = entry.value;
event.process();
}
}
public void killEvent(TimedEventEnum event) {
hshTimedEvent.remove(event);
}
// TimedEventEnum.java
public enum TimedEventEnum {
COUNT_MONEY,
CHECK_FOR_ACHIEVS,
ANOTHER_EVENT_EXAMPLE
}
//CountMoneyTimedEvent.java
public class CountMoneyTimedEvent extends Timer implements TimedEvent {
public CountMoneyTimedEvent() {
super();
init(this, 4f, false);
}
#Override
public void execute() {
//execute logic here
}
#Override
public void reset() {
this.timesFired = 0L;
}
}
//Timer.java
public abstract class Timer {
private Float deltaCount;
private Float timeToEvent;
private Boolean isRepeatable;
protected Long timesFired;
private TimedEvent event;
Timer() {
}
public void init(TimedEvent event, Float eventTime, Boolean isRepeatable) {
this.deltaCount = 0f;
this.timeToEvent = eventTime;
this.isRepeatable = isRepeatable;
this.timesFired = 0L;
this.event = event;
}
public void process() {
if (isEventTime()) {
event.execute();
}
}
private Boolean isEventTime() {
if (event != null && (isRepeatable || timesFired == 0)) {
deltaCount += Gdx.graphics.getRawDeltaTime();
if (deltaCount > timeToEvent) {
deltaCount -= timeToEvent;
timesFired++;
return true;
}
}
return false;
}
protected void executeNextEvent() {
deltaCount = timeToEvent;
}
}
// TimedEvent.java
public interface TimedEvent {
void execute();
void reset();
void process();
}
I have a sub class of RecursiveTask which contains a Runnable object and should execute it.The problem is that the code inside the run method never gets reached although I use ForkJoinPool.execute in order to not block the main thread.
public class test {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
Display.getDefault().syncExec(new Runnable() {
#Override
public void run() {
System.out.println("lo");
}
});
}
};
ATLockTask t = new ATLockTask();
t.runnable = r;
new ForkJoinPool().execute(t);
}
}
public class ATLockTask extends RecursiveTask<Object>{
public Runnable runnable;
#Override
protected Object compute() {
try {
runnable.run();
} catch (Exception e) {
logger.catching(e);
}
return null;
}
}
My goal is to change the screen of a user when the game can't reach the backend anymore. My code executes as expected except the screen never changes. Here's the initial call:
timer.testTimeToServer(api, game);
Here's the timer object's class. I put (my url) in place of the actual IP address of my backend:
public class CustomTimer {
private static final float timeToDrop = 2000;
private float time = 0;
private StopWatch watch = new StopWatch();
public void testTimeToServer(ApiCall api,final proofOfConcept game){
watch.start();
api.httpGetWithCallback("(my url)/api/v1/character", new CallBack(){
#Override
public void callback(String resp){
System.out.println("Server Responded");
time = watch.getTime();
watch.stop();
watch.reset();
if(time > timeToDrop){
game.setScreen(new GameOverScreen(game, false));
System.out.println("Should have switched screen")
}
}
});
}
}
Here's the httpGetWithCallback method in the api object:
public void httpGetWithCallback (final String URL, final CallBack callback){
Thread th = new Thread(new Runnable(){
#Override
public void run() {
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Net.HttpRequest httpRequest = new Net.HttpRequest(Net.HttpMethods.GET);
httpRequest.setUrl(URL);
httpRequest.setHeader("Content-Type", "application/json");
httpRequest.setTimeOut(timeoutTimeInMilli);
Gdx.net.sendHttpRequest(httpRequest, new Net.HttpResponseListener() {
#Override
public void handleHttpResponse(Net.HttpResponse httpResponse) {
String successValue = httpResponse.getResultAsString();
if (successValue.contains("\"total_count\": 0"))//wrong credentials
{
callback.callback("EMPTY");
} else//there was a match yo! should probably have a unique conststraint on username. too hard eff it
{
callback.callback(successValue);
}
}
#Override
public void failed(Throwable t) {
callback.callback("FAILED");
}
#Override
public void cancelled() {
callback.callback("CANCELLED");
}
});
}
}
);
}
});
th.start();
threads.add(th);
}
I'm stumped because the code prints out "Should have switched screens" so it's acting like expected except for the fact that the game is frozen up and the screen switch never actually happens.
The Lazy Way:
on your main game class:
public static ProofOfConcept game;
and your method
public void testTimeToServer(ApiCall api){
watch.start();
api.httpGetWithCallback("(my url)/api/v1/character", new CallBack(){
#Override
public void callback(String resp){
System.out.println("Server Responded");
time = watch.getTime();
watch.stop();
watch.reset();
if(time > timeToDrop){
Main.game.setScreen(new GameOverScreen(false));
System.out.println("Should have switched screen")
}
}
});
}
}
The Right Way
You can create a callback inside your ProofOfConcept class that every frame on the render method checks the result and change the screen.
i'm trying to make a void with a Void as an argument in libgdx,
how do i make it work?
this is what i have:
public class ReleaseDetector{
boolean Touched = false;
//
// --- Simple void for touch release detection, when looped. ---
// --- and the argument void, or how i imagine it..
//
public void ReleaseListener(void MyArgumentVoid)//<---The argument void
{
if (Gdx.input.isTouched()){
Touched = true;
}
if (!Gdx.input.isTouched() && Touched){
MyArgumentVoid();<----------// Call for a void from the Argument.
Touched = false;
}
}
}
Usage in MyGdxGame class, or how i imagine it:
public class MyGdxGame extends ApplicationAdapter {
int Counter = 0;
ReleaseDetector RD = new ReleaseDetector();
public void AddCounter(){// just a simple void.
Counter++;
}
#Override
public void render() { // Render Loop void.
RD.ReleaseListener(AddCounter);// how i imagine it's usage.
}
}
now, how am i making it real? i hope there is a simple way..
It seems that you need a callback method which takes no argument and returns void.
public class ReleaseDetector {
boolean touched = false;
public void releaseListener(MyGdxGame game) { // Argument
if (Gdx.input.isTouched()) {
touched = true;
}
if (!Gdx.input.isTouched() && touched){
game.addCounter(); // Callback
touched = false;
}
}
}
public class MyGdxGame extends ApplicationAdapter {
int counter = 0;
ReleaseDetector detector = new ReleaseDetector();
public void addCounter() {
counter++;
}
#Override
public void render() { // Render Loop.
detector.releaseListener(this);
}
}
Hope this helps.
I have a problem with the ScheduledThreadPoolExecutor.
I need a timeout which will redirect to the first page after 'n'-seconds. If the user enters a character, the timer should start counting again and may not redirect to the first page.
(So the counter should abort his scheduled Task)
The Problem is, that the Timer starts, but it doesn't cancel the scheduled Task if a key was typed. The stop() - Method will be called. But scheduledThreadPool.shutdownNow(); seems not to work.
My TimerClass looks like this:
public class MyTimer {
private final Runnable logicalWorker;
private final long delay;
private final ScheduledThreadPoolExecutor scheduledThreadPool;
public MyTimer(final Runnable logicalWorker, final long delay) {
scheduledThreadPool = new ScheduledThreadPoolExecutor(1);
this.logicalWorker = logicalWorker;
this.delay = delay;
}
public void start() {
scheduledThreadPool.schedule(logicalWorker, delay, TimeUnit.SECONDS);
}
public void stop() {
scheduledThreadPool.shutdownNow();
scheduledThreadPool.getQueue().clear();
}
public void restart() {
start();
}
public boolean isScheduled() {
return !scheduledThreadPool.isTerminated() && !scheduledThreadPool.isShutdown();
}
}
The method in a superclass which calls the timerClass is this one:
protected void startTimeout() {
if (currentInstance.getAutoTimeout() != null && currentInstance.getAutoTimeout().isScheduled()) {
currentInstance.getAutoTimeout().restart();
return;
}
currentInstance.setAutoTimeout(new MyTimer(new Runnable() {
#Override
public void run() {
Platform.runLater(new Runnable() {
#Override
public void run() {
if (!PageContent.PAGE_ID.equals(currentInstance.getPageId()) && !forceOpen) {
cancelCurrentProcesses();
switchPageByPageId(PageContent.PAGE_ID);
}
}
});
}
}, currentInstance.getPageDelay()));
if (currentInstance.getPageDelay() > 0) {
currentInstance.getAutoTimeout().start();
}
}
The KeyListener and the MouseClickListener will be set on the scene at the beginning by this method:
protected void placePage() throws SecurityException, IllegalArgumentException, IllegalAccessException,
InstantiationException, NoSuchMethodException, InvocationTargetException {
startTimeout();
currentInstance.getRoot().setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
startTimeout();
}
});
currentInstance.getRoot().setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent arg0) {
startTimeout();
}
});
}
Take a look at this -> http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html
The shutdownNow() makes no guarantees to cancel execution.
As for a solution, I recommend you use ScheduledFuture or Future objects rather than Runnable.
[EDIT] A scheduled future, on which you can call a .cancel() function instead of .shutdownNow() is returned by the .schedule() call, which you call, but don't seem to use (or indeed save) the handle to the Future anywhere. And yes, you do still need a Runnable but only insofar as it will give you the Future handle.
Try something like this:
private ScheduledFuture<?> future;
public void start() {
future = scheduledThreadPool.schedule(logicalWorker, delay, TimeUnit.SECONDS);
}
public void stop() {
if(future != null) future.cancel();
}
[/EDIT]
More details here -> http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledFuture.html