CountdownTimer is not Running in Runnable - java

Hello Developers This question may seem foolish to some readers and it may have answered before but I have seen many answers on this forum regarding my issue but I could not understand single one of them. So please be kind and answer my question if you could.
The thing is I am trying to develop something like a game and trying to add computer or AI player against a human player.
For that I added a CountdownTimer in OnCreate method and it worked fine only once as OnCreate executes only once. But when I tried to add a while loop inside a runnable and inside that while loop I added the same CountdownTimer but it started giving me errors.
if(player2_name.equals("Computer")) {
Runnable r = new Runnable() {
#Override
public void run() {
while (player2_name.equals("Computer")) {
CountDownTimer computer_player;
ct = 5;
firstplayer_game_button.setClickable(false);
computer_player = new CountDownTimer(5000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
ct = ct - 1;
// timer_counter.setText("" + ct);
if (ct == 1) {
firstplayer_game_button.setClickable(true);
}
}
#Override
public void onFinish() {
// secondplayer_game_button.setBackgroundResource(R.drawable.button_player_2);
// firstplayer_game_button.setBackgroundResource(R.drawable.button_player_1);
// firstplayer_game_button.setClickable(true);
if (player2_name.equals("Computer")) {
secondplayer_game_button.setClickable(false);
} else {
secondplayer_game_button.setClickable(true);
}
if (checker != 1) {
Click_Condition_checker(2);
}
}
};
computer_player.start();
}
}
};
Thread mythread = new Thread(r);
mythread.start();
I know that a Runnable cannot interact with UI directly and for that we need handlers that is why I commented all the UI interfaces. But still no luck. And unfortunately I am not able to identify the errors. If Someone can help then it would be very kind for a foolish developer like me.

First, you don't need to use Runnable to make a CountDownTimer works. It's because CountDownTimer can directly interact with the UI if the code running inside the Activity.
Second, you should not use while loop inside your code. Especially for the following code:
while (player2_name.equals("Computer")) {
CountDownTimer computer_player;
...
computer_player = new CountDownTimer(5000, 1000) {}
...
}
which means you're creating new object until you exhausted all the device memory or until player2_name is not "Computer".
You should using a boolean flag instead.
I think what you need is can be achieved by restarting the CountDownTimer with something like this:
// use a more readable variable name instead of computer_player
final CountDownTimer cdtPlayer = new CountDownTimer(5000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
// do something
}
#Override
public void onFinish() {
// do something
// restart to do all again
cdtPlayer.start();
}
};
cdtPlayer.start();
Regarding your following statement:
If Someone can help then it would be very kind for a foolish developer like me.
Everybody is a foolish when starting to learn something. Don't be too hard with yourself ;)

Not sure about your goal but your while loop seems troublesome. A while testing a string and not changing its value, it's going to run over and over (and by then create that many CountdownTimer which I don't think was your intent)

Related

Hit counter approach with Servlets

I want to create a hit counter register in my DB using Java Servlets. The main idea is use Filters and, in every user visit, increase the counter.
I don't want to make an update in the DB on every visit (I found this not too much efficient). I prefer to use an static variable that would be increased every visit and, at the end of the day, make an INSERT into the DB with the value of that variable and reset it to zero.
How could I do that? I don't know how to schedule an accion that say to my application every midnight make an INSERT and resets the variable...
Any idea?
Thank you! :)
You can use java.util.Timer
Timer t = new Timer("myTimer");
t.schedule(new TimerTask() {
#Override
public void run() {
if (count != lastCount) {
count = lastCount;
// TODO: update into database
}
}
}, 0, 2000);
After a long time searching for solutions, I found that Timer is not working well with Servlets, so I used this (and works great! :) This is the code for the filter:
public class LogVisitorsListener implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent sce) {
scheduler = Executors.newSingleThreadScheduledExecutor();
// It will be executed every 1 hour
scheduler.scheduleAtFixedRate(new DailyHitsRunnable(), 0, 1, TimeUnit.HOURS);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
scheduler.shutdownNow();
}
}
And my class DailyHitsRunnable:
public class DailyHitsRunnable implements Runnable {
#Override
public void run() {
try {
// stuff here...
}
catch(Throwable t) {
// catch work here...
}
}
}
It's very important to use that try/catch to avoid stopping the runnable action stops when something fails.
Regards!

Local fields from outer class unaffected by Runnable code

This has been killing me lately. I'm making a quick settings tile that should show as active or inactive based on whether it can communicate with a specific machine over a socket. Here are my declarations:
public class WakeUpTileService extends TileService {
private static volatile boolean online;
private final TimerTask timerTask;
private Timer timer;
Here's the constructor:
public WakeUpTileService() {
super();
online = true;
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
boolean shouldBeOn = false;
try {
Socket s = new Socket();
// 3000 is the timeout in milliseconds.
s.connect(myInetSocketAddress, 3000);
// Connection was successfully established.
s.close();
shouldBeOn = true;
} catch (Exception e) {
// Connection failed.
// shouldBeOn is already false.
} finally {
if (shouldBeOn != WakeUpTileService.online) {
WakeUpTileService.online = shouldBeOn;
// This method causes onStartListening() to be called
// on the main thread so I can update the Tile.
requestListeningState(
getApplicationContext(),
new ComponentName(
getApplicationContext(),
WakeUpTileService.class
)
);
}
}
}
};
}
Here's where the timer gets started:
#Override
public void onTileAdded() {
super.onTileAdded();
timer.scheduleAtFixedRate(timerTask, 0, 60000);
// At the moment I have it checking once per minute
// For debugging purposes. I plan to make it less frequent.
}
And here's the code that uses the value of online to update the Tile. This gets called on the main thread after WakeUpTileService.online = shouldBeOn; in the TimerTask.
#Override
public void onStartListening() {
Tile t = getQsTile();
if(WakeUpTileService.online)
t.setState(Tile.STATE_ACTIVE);
else
t.setState(Tile.STATE_INACTIVE);
t.updateTile();
}
When I step through the code in the debugger, the TimerTask code is definitely finished before onStartListening gets called, and within the context of the TimerTask, online holds the correct value. Then, when onStartListening is called, online seems to revert to the value it had at the beginning.
Thoughts I've had about what might be going on:
The online being referenced in WakeUpTileService is somehow not the same object as is being referenced in the Runnable code (that's why I made online static and used WakeUpTileService.online instead of just online.)
The assignment to online is actually not happening before online is read by onStartListening(). Again, when I stepped through the code with the debugger, this doesn't appear to be happening, and just by looking at the code below, this doesn't seem reasonable.
I don't know what else could be happening here. Please help!
Update: korolar suggested that the two classes might have been loaded by different classloaders, and after some investigation, I found that that is the cause. My service is being loaded by dalvik.system.PathClassLoader and java.util.Timer is being loaded by java.lang.BootClassLoader. I don't, however, know how to work around or solve this issue. Can anyone provide some suggestions?
In case anyone else runs into this problem, I'll let you know what I eventually did to fix it.
Apparently using the java.util.Timer class at all is generally bad practice in Android programming. Instead, I rewrote my program using the Android AlarmManager class and IntentService. That completely bypasses the classloader problem.

Runnable concurrency

I am playing around with JMonkeyEngine.
While doing this i play JavaFX MediaPlayer.
This MediaPlayer takes a Runnable to handle what's to do, when the media finished:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
}}
I want to do sth. like this:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
// instance.toggleLists();
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
this is working a couple of times, but finally i am running into some runtime error.
java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call.
Make sure you do not modify the scene from another thread!
Problem spatial name: Root Node
Yeah, that's true. I am messing up that thread from the outside.
As i am a little bit unused to this stuff...
I don't need to do that thing at that location in that run method, it's just what has to be done,when this is running.
What is the best way to pass over the work so that my ordinary update call can do that housework ?
I already tried to build in a flag, setting that to true and when true, updating that by the standard update call from the application itself, but somehow i ever run into this error. That didn't help me much.
The MediaPlayer just needs to tell my App "Hey! I'm ready! Give me a break and change me to something new!"
That is, what is happening in that run method.
You can use Application.enqueue to make a Runnable run on the main thread in the next update - like so: (assuming app is a reference to the Application)
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
app.enqueue(new Runnable() {
#Override public void run() {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
}
});
If you're using Java 8, you can abbreviate this using lambda expressions:
mp.setOnEndOfMedia(() -> {app.enqueue(() -> {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}});

Waiting two minutes to call a method

I'm working on a Minecraft Bukkit plugin, I know how to handle events and everything, but I'm not sure how to do this. I haven't actually written the code yet so here's a basic example of what I want to do:
public void playerDead() {
runCommand(commandHere)
//Wait 2 minutes.
runCommand(otherCommandHere
}
I just need the part to wait two minutes. Everything else is covered.
EDIT2: Seems I need to reset the delay to the beginning if someone else dies while it's going. Any suggestions?
Since I see you want to perform your action after the player has died. Then for sure you don't want to halt the main Thread with Thread.sleep(x);
What you can do is create a cooldown for the player that passed away.
public Map<String, Long> cooldown = new HashMap<String, Long>();
Long time = cooldown.get(player.getName());
if(time - System.currentTimeMillis() > 10*1000)
cooldown.put(player.getName(), System.currentTimeMillis());
else
int remains = (int)Math.floor(10 - System.currentTimeMillis());
Code reference here.
Or you can create your task to run like this:
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable()
{
public void playerDied()
{
// Your code here.
}
}, <delay in ticks>);
Get a reference to your plugin and pass it as the parameter plugin. Or if you are lazy just write it inside the plugin and pass it this.
You should use the BukkitScheduler provided by Bukkit.
You have to save the BukkitTask object returned by the Scheduler.runTaskLater(...) method to use it later.
Every time playerDead() is called, you can reset the delay by cancelling and restarting the task.
BukkitTask task;
public void playerDead() {
// Command here
if (task != null) {
task.cancel();
}
task = getServer().getScheduler().runTaskLater(Plugin, new Task(), 2400L);
}
public class Task extends BukkitRunnable {
#Override
public void run() {
// Other command here
task = null;
}
}
You may try like this:
new Timer().schedule(new TimerTask() {
#Override
public void run() {
runCommand(commandHere);
}
}, 120000);

Can't create handler inside thread. How do I use Looper.prepare()? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can’t create handler inside thread that has not called Looper.prepare() inside AsyncTask for ProgressDialog
I'm developing an Android service that try to obtain the device IP address every x time and comunicate it to a server.
I'm using:
Netbeans 7.2Android SDKAndroid Google-Api 8SQLite
I know there are a few questions related to this same issue, but none of them gave me a solution to my problem. As you can see in my code below, I'm not trying to access to the UI of the service main thread (well, I tried, but after I commented the line, the error remains the same). On the other hand, I'm using AsyncTask, which I think is the appropriate way to do it.
This is the main part of my service:
public class ArsosService extends Service {
private NotificationManager mNM;
private final Messenger mMessenger = new Messenger(new IncomingHandler());
protected DatabaseUtil dbu = null;
#Override
public void onCreate() {
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
try {
dbu = DatabaseUtility.getInstance(this);
} catch (IOException ex) {
Log.e("Service", ex);
}
Timer timer = new Timer();
timer.schedule(new Checks(), 0, 15000);
}
private class Checks extends TimerTask {
#Override
public void run() {
CheckIpAddress_Task checkIp = new CheckIpAddress_Task();
checkIp.execute();
}
}
// Other methods
private class CheckIpAddress_Task extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... arg0) {
String ipLocal = getLocalIpAddress();
String text = null;
// ipLocal==null means there is no available connection, so we do nothing.
if (ipLocal != null) {
String ipDb = dbu.getLastIP(); // we get the IP saved in the DB.
if (ipDb == null) {
dbu.addProperty("IP", ipLocal); // we save the IP in the DB.
} else if (!ipLocal.equals(ipDb)) {
dbu.setProperty("IP", ipLocal); // we update the IP in the DB.
}
}
if (text != null) {
//showNotification(1, text, ipLocal);
}
return 0;
}
private String getLocalIpAddress() {
String result = null;
// Irrelevant code
return result;
}
}
}
I think the problem may be related to the threads, but I can't see where. Any help will be appreciated.
EDITED: Although I have accepted one of the answers as correct, or maybe because of it, I've been searching for some more information regard to it. I've run into this page I want to share with all of you who someday need to know more about this issue. Its author,Tejas Lagvankar, explains everything about threads, loopers and handler in a very clear and understandable way.
Try this...
- First declare the Handler Object reference variable at class scope.
Handler h;
- Inside the onCreate() method create the instance of the Handler.
h = new Handler();
- Use it with thread like below:
new Thread(new Runnable(){
public void run(){
h.post(new Runnable(){
// Do the UI work here.
});
}
});
- You can very well use the AsyncTask, provided in android, its known as P*ainless threading.*
Handler always runs in the Looper thread context. When you declare a seperate thread, its context is different from the Looper. Hence the error.
Simple solution is always declare Handlers in onCreate(), onStart() and onResume(). If you use AsyncTasks, you can very well declare handlers in onPreExecute() and onPostExecute() as they too run in the Looper context.

Categories

Resources