I'm new to Java so sorry if the problem is trivial. My code is probably a mess. I created a online radio player for Raspberry Pi in Java and I have to do a POST request every 10 seconds to check what is the current song playing and if the song has changed, I have to do some things (like scrobble old song, update display with new song data, store play session to my server etc.). I created a class for this:
public class Scrobbler implements Runnable, Commands, Observer {
private TimeCounter counter;
private Timer timer;
private Radio radio;
private List<Observer> observers;
private final Object MUTEX= new Object();
private int currentPlaySession;
// And all other variables which I deleted before posting
// Constructor
public Scrobbler(TimeCounter _counter, Radio _radio)
{
currentTrack = null;
counter = _counter;
radio = _radio;
timer = null;
observers = new ArrayList<>();
currentPlaySession = 0;
}
private void GetInfo()
{
// POST request to get current song playing
// If song has changed, notify observers
}
public void Scrobble()
{
// POST request - Scrobble song to my website and last.fm
}
public void StartPlaySession()
{
// Again POST request to my website
}
public void EndPlaySession()
{
// Again POST request to my website
}
#Override
public void start() {
new Thread(this).start();
}
public void stop()
{
timer.cancel();
timer.purge();
timer = null;
}
#Override
public void register(Observer obj) {
if(obj == null) throw new NullPointerException("Null Observer");
synchronized (MUTEX) {
if(!observers.contains(obj)) observers.add(obj);
}
}
#Override
public void unregister(Observer obj) {
synchronized (MUTEX) {
observers.remove(obj);
}
}
#Override
public void notifyObservers(String command) {
for (Observer obj : observers) {
obj.update(command);
}
}
#Override
public void run() {
timer = new Timer();
timer.schedule(new TimeOut(), 0, 10000);
GetInfo();
StartPlaySession();
}
public class TimeOut extends TimerTask
{
#Override
public void run() {
EndPlaySession();
GetInfo();
}
}
#Override
public void update(String command) {
if ("RADIO_STARTED".equals(command))
{
this.start();
}
if ("RADIO_STOPPED".equals(command))
{
this.stop();
if (this.currentTrack != null && this.counter.getTrackTime() >= 60)
this.Scrobble();
EndPlaySession();
}
}
private void handleException(String message)
{
try {
String timeStamp = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("/home/pi/OnlineRadio/error_log.txt", true)));
out.println("(" + timeStamp + ") [SCROBBLER] - " + message + "\n\n\r");
out.close();
} catch (IOException e) {}
this.stop();
this.start();
}
}
I create a new instance of Scrobbler in my main method and register it as an observable to player. Once I start the radio, player will notify its observers (including instance of Scrobbler class) by calling update() method and forward "RADIO_STARTED" or "RADIO_STOPPED" (after starting or stopping the radio). As you can see in code, on RADIO_STARTED, a start() method is called where new Thread is started. Starting a new thread is probably unnecessary here since it only starts the timer but it shouldn't be a problem neither. After starting the timer, every 10 seconds method run() in class TimeOut will be called which then calls necessary methods.
This code works but sometimes it just stops for no reason. All other parts of application continue to work (music is still playing, application reacts on buttons etc.), just it doesn't update the song and there's no communication with my website at all so not even one of these methods is called, just like the timer stopped. When I stop and start the radio again or change the station, it works again (as you can see in code, the timer will be stoped every time the radio stops and the timer will start everytime the radio starts), but it will break again after some time.
Since I have a lot of try-catch blocks in those methods with POST requests, at first I thought that there must be an exception occuring and killing the timer thread so I created the handleException() method which logs exception message to a file and restarts this timer (you can see in code), and then I handle exceptions like this, for example:
try {
writer.close();
} catch (IOException e) {
this.handleException(e.getMessage());
}
But when the problem occured again, log file was empty, which means that not even one exception occured. I also tried to log all the data everytime the song changes and everything is fine, it just stops after a while for no reason. And I can't find a regularity in occuring, sometimes it occurs after a few minutes and sometimes if works for hours before it breaks.
This app runs on Raspberry Pi model B, and I don't know if this means something, but it's in JAR and it starts with the Pi (via cron #reboot) since I don't have any monitor nor keyboard/mouse on this Pi, so the app must start with it and run in background all the time. And I use SSH to transfer the JAR to Pi and to read log files.
Somewhere I read that it's not uncommon for the Java timer to stop without any reason. But how to solve this?
Related
Edit
I figured it out:
The order in which I initialized the Service members was important! Other members (not shown in my examples) reference the Timer in Runnables by calling the Service getter getTimer() (not shown either). In this getter the listener is registered, but not initialized yet, because it was declared/initialized after the other members, not before them. Sigh...
I have a class Service and an inner class Timer which runs in a separate thread. This timer accepts a tick listener, which is called at fixed intervals when the timer is running.
The gist of it is this:
public class Service {
private Timer timer;
Service() {
// more to follow in code snippets below where I demonstrate the issue I am facing
}
private static class Timer
implements Runnable {
private interface TickListener {
void onTick(Timer timer);
}
private TickListener tickListener;
public void setTickListener(TickListener tickListener) {
this.tickListener = tickListener;
}
public void start() {
new Thread(this).start();
}
#Override
public void run() {
while(keepThreadRunningCondition) {
if(tickListener != null) {
// to verify that Timer is actually running
// and tickListener is not null
// I actually log here
// and the log appears just fine in all cases
tickListener.onTick(this);
}
}
}
}
}
Now, when I register the tick listener anonymously, like so:
class Service {
private Timer timer;
Service() {
timer = new Timer();
timer.setTickListener(new Timer.TickListener() {
#Override
void onTick(Timer timer) {
// this gets called perfectly fine
}
});
}
}
...the listener gets called just fine, when the timer is started.
However, when I register the tick listener as a member of my Service class, like so (I've tried a couple of different permutations of public, final, volatile, etc. as well):
class Service {
private Timer timer;
private Timer.TickListener timerTickListener = new Timer.TickListener() {
#Override
void onTick(Timer timer) {
// this will NOT get called
}
};
Service() {
timer = new Timer();
timer.setTickListener(timerTickListener);
}
}
...the listener does not get called, when the timer is started.
I suspect this issue is related to multithreading, because similar setups work just fine when not spanning different threads, but I'm not well-versed enough in multithreading to understand exactly why this is not working.
Can you shed a light on this issue?
Does it have something to do with accessing objects by reference across different threads, perhaps? Or is it something different?
You claimed that upon registering TickListener as Service's member variable, onTicket will not get called.
This was not correct. I ran the code myself and it got called.
Here is my code,
package com.company;
public class Service {
private Timer timer;
Timer.TickListener tickListener = new Timer.TickListener() {
#Override
public void onTick(Timer timer) {
// this gets called perfectly fine
System.out.println(42);
}
};
Service() {
// more to follow in code snippets below where I demonstrate the issue I am facing
timer = new Timer();
timer.setTickListener(tickListener);
}
private static class Timer
implements Runnable {
private interface TickListener {
void onTick(Timer timer);
}
private TickListener tickListener;
public void setTickListener(TickListener tickListener) {
this.tickListener = tickListener;
}
public void start() {
new Thread(this).start();
}
#Override
public void run() {
while(true) {
if(tickListener != null) {
// to verify that Timer is actually running
// and tickListener is not null
// I actually log here
// and the log appears just fine in all cases
tickListener.onTick(this);
}
try{
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void foo() {
timer.start();
}
public static void main(String[] args) {
Service service = new Service();
service.foo();
}
}
I am trying to make a text to speech thread stop whenever the talk(String text, boolean voiceEnabled) method is called from an ActionEvent using buttons.
When these buttons are pressed different text Strings are passed to the method, which runs the audio on a new thread. If the current thread is still running but a new ActionEvent occurs I need the current thread to stop (i.e the text-to-speech) so that the new text-to-speech audio can be played without the current audio clip and new clip playing over the top of eachother.
This is what I currently have but the TTS audio are playing over the top of eachother. I need the current TTS to stop as soon as a new TTS is triggered. I believe my main problem is that a new Thread is being made each time the method is called.
Any help greatly appreciated. Thanks!
public void talk(String text, boolean voiceEnabled) {
System.out.println(text);
// Create a new Thread as JLayer is running on the current Thread and will
// make the application lag
Thread thread = new Thread(() -> {
try {
// Create a JLayer instance
AdvancedPlayer player = new AdvancedPlayer(synthesizer.getMP3Data(text));
if (voiceEnabled) {
player.play(); //Plays the TTS audio
System.out.println("Successfully retrieved synthesizer data");
}
else {
}
} catch (IOException | JavaLayerException e) {
e.printStackTrace();
}
});
// We don't want the application to terminate before this Thread terminates
thread.setDaemon(false);
// Start the Thread
thread.start();
}
You appear to be burying key references inside of anonymous inner classes, and I don't see how you can get to them when and if needed. Why do this? Why not create an instance of a non-anonymous class, one with an AdvancedPlayer field, one whose reference is held by some collection, perhaps a List<...> or a HashMap, or by a variable if only one to two are running, where you can extract the object, get its AdvancedPlayer field and call .stop() on it?
e.g.,
public class RunnablePlayer implements Runnable {
private AdvancedPlayer player;
private String text;
private boolean voiceEnabled;
public RunnablePlayer(String text, boolean voiceEnabled) {
this.text = text;
this.voiceEnabled = voiceEnabled;
}
#Override
public void run() {
try {
// Create a JLayer instance
player = new AdvancedPlayer(synthesizer.getMP3Data(text));
if (voiceEnabled) {
player.play(); //Plays the TTS audio
System.out.println("Successfully retrieved synthesizer data");
}
} catch (IOException | JavaLayerException e) {
e.printStackTrace();
}
}
public AdvancedPlayer getPlayer() {
return player;
}
public void stop() {
// perhaps do a null check here first?
if (player != null) {
player.stop();
}
}
}
Then you could have a field of the class, something like:
// field of the class
private RunnablePlayer runnablePlayer;
and use this in your talk method:
public void talk(String text, boolean voiceEnabled) {
if (runnablePlayer != null) {
runnablePlayer.stop(); // not calling this on a Thread
}
runnablePlayer = new RunnablePlayer(text, voiceEnabled);
Thread thread = new Thread(runnablePlayer);
//.....
thread.start();
}
Code not compiled or tested, but is presented to just give a general idea.
I have a CustomAsyncTask class that enables infinite barcode scanner and I execute it in CustomApplication.
Unfortunately CustomAsyncTask::doInBackground stops after some time (minute or two).
private class ScanAsync extends AsyncTask<Void, String, Void>
{
boolean blocked = false;
#Override
protected Void doInBackground(Void... params)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
blocked = true;
publishProgress(received);
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
#Override
protected void onProgressUpdate(String... values)
{
super.onProgressUpdate(values);
//TODO: something with received value
blocked = false;
}
}
I need this background task to be always on. Is there any good solution for this? I have tried IntentService, but the result was the same - after some time it stopped working.
EDIT
I have created this Service, although it block my main thread, but it should work in background right? Also If I put a breakpoint on if(!blocked) and press F9 it works fine (scanning part), but if I remove breakpoint and let it run - after few seconds it just turns off (scanner), but if I put a breakpoint again - it works again (sic!).
public class ScanService extends Service
{
boolean blocked = false;
public ScanService()
{
}
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
//blocked = true;
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
}
Use a Service instead of AsyncTask. AsyncTasks are only designed to run with shorter background tasks. Keep in mind that whatever you run in a Service will execute on the main thread, so you should use a background thread within your Service.
Can you tell why the AsyncTask or IntentService is stopping? With an IntentService, with your while(true) loop, it should run indefinitely unless the app gets shut down for some reason.
Edit -
You need to do this to prevent your loop from blocking the main thread -
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(true) {
// your code here
}
}
});
t.start();
}
I don't know why your Service is stopping. You need to be looking at your Logcat output. Set the filter to Error and you're crash should show up there.
Yes, there is an elegant solution for this type of thing. Use a service. In particular, the JobScheduler api is meant to handle this kind of stuff. Reason for using this is, as you stated, you have a long running task and you don't want to have to manage it dying. In addition, the JobScheduler is built to handle side effects of the OS. I assume that you want your job to run, but allow the app to perform its normal set of operations. Though, as a note, the API is smart in considering factors, such as battery levels, OS resources being used, wifi connectivity, so the jobs can be deferred.
The official documentation is here https://developer.android.com/reference/android/app/job/JobScheduler.html
An example of how to use it can be found here
https://code.tutsplus.com/tutorials/using-the-jobscheduler-api-on-android-lollipop--cms-23562
I have an event listener which detects when the mouse is being moved in a certain pane of my program. From this, I want to be able to perform some action if the mouse stays idle for too long.
I have looked all over earlier today, to try and find an explanation and example which details how to start, stop/cancel and reset a timer but have been bombarded with different ways to try and do this, which has left me quite confused.
I'm following a timer example from here and implementing for my own situation
When this code below is run, it will output "A" every time the mouse stops. This is incorrect, as if I stop the mouse, move it quickly then stop it again, 2 sets of "A" are produced.
This carries on for however many times the stop is produced.
I believe I am missing a 'reset timer' function that will called when the mouse changes to a moving state.
How can I implement this?/Is that even the problem?
public class SomeClass{
//...some fancy code...
if (! isNowMoving) {
System.out.println("Mouse stopped!");
//Start Timer
new PrintingA(5);
} else if (isNowMoving){
System.out.println("MouseMoving");
//cancel timer & reset ready to start
}
public class PrintingA {
Timer timer;
public PrintingA(int seconds) {
timer = new Timer();
timer.schedule(new PrintingTask(), seconds * 1000);
}
class PrintingTask extends TimerTask{
#Override
public void run() {
System.out.println("A");
timer.cancel();
}
}
}
}
I'm not sure this can be useful for your requirement, Timer is a facility for threads to schedule tasks for future execution in a background thread. Tasks may be scheduled for one-time execution, or for repeated execution at regular intervals. Read java document : java.util.Timer
I perfer to have a thread for IdleMonitor and use Apache Stopwatch to monitor idle time.
import org.apache.commons.lang3.time.StopWatch;
public class IdleMonitor implements Runnable {
StopWatch stopWatch;
private final Object monitorObj = new Object();
private boolean isActive;
private long waitTime = 6000; //in milliseconds, put appropriate time to wait
public IdleMonitor() {
isActive = true;
stopWatch = new StopWatch();
}
public void reset() { // call this during MouseMoving event
synchronized (monitorObj) {
stopWatch.reset();
monitorObj.notify();
}
}
public void finish() { // finish idle mointor operation once your operation ends, this will stop the thread
isActive = false;
reset();
}
public void start() { // start monitoring
Thread t = new Thread(IdleMonitor.this);
t.start();
}
#Override
public void run() {
synchronized (monitorObj) {
stopWatch.start();
while (isActive) {
try {
monitorObj.wait(waitTime);
} catch (InterruptedException ex) {
}
long idleTime = stopWatch.getTime();
System.out.println("Idle time " + idleTime);
// do something if idle time beyond your expected idle time.
// you could set isActive=false; if you want to stop monitoring
}
}
}
}
}
I'm working on making an interface for a robot. My Robot class has methods that include movement, stopping movement and reading sensor data. If at all possible, I'd like to have certain methods run under a given thread and certain other methods run under another. I'd like to be able to send the command to move to the robot object, have the thread executing it sleep duration milliseconds and then stop movement, but I'd like the stop() method able to be called and interrupt the thread executing the movement. Any help is greatly appreciated.
public class robotTest
{
public static void main(String[] args) throws InterruptedException
{
Robot robot = new Robot(); //Instantiate new Robot object
robot.forward(255, 100, Robot.DIRECTION_RIGHT, 10); //Last argument representing duration
Thread.sleep(5000); //Wait 5 seconds
robot.stop(); //Stop movement prematurely
}
}
I would suggest instantiating your Robot class with an ExecutorService that you can use for moving asynchronusly. Submit the movement request to your service and use the Future returned to 'stop' the move request.
class Robot{
final ExecutorService movingService = Executors.newSingleThreadExecutor();
private volatile Future<?> request; //you can use a Deque or a List for multiple requests
public void forward(int... args){
request = movingService.submit(new Runnable(){
public void run(){
Robot.this.move(args);
}
});
}
public void stop(){
request.cancel(true);
}
}
If I'm understanding you correctly then yes, you can call methods on an object from any given thread. However, for this to work in a bug free fashion the robot class needs to be thread safe.
Make sure all your calls to Robot come from a thread (a class extending Thread that you create) with permissions to make the calls. Add this method to your call.
Note: this code is far from perfect. But it may give you some ideas you can use in your application.
public void stop() throws NoPermissionException {
checkStopPermission(); // throws NoPermissionException
// rest of stop here as normal
}
/**
* Alternatively you could return a boolean for has permission and then throw the NoPermissionException up there.
*/
private void checkStopPermission() throws NoPermissionException() {
try {
Thread t = Thread.currentThread();
RobotRunnableThread rrt = (RobotRunnableThread)t; // may throw cast exception
if(!rrt.hasPermission(RobotRunnableThread.STOP_PERMISSION)) { // assume Permission enum in RobotRunnableThread
throw new NoPermissionExeception();
}
} catch(Exception e) { // perhaps catch the individual exception(s)?
throw new NoPermissionException();
}
}
You have to start a new background thread when you instantiate a Robot that would handle movement. The thread would sit there, waiting for a signal from forward or stop and do the appropriate thing.
You will have to synchronize the threads using either semaphores, wait handles, or other inter thread communication elements.
The least robust solution that wastes the most CPU (this is pseudo code since I have not used Java in a while, might be intermixed with .NET APIs):
public class Robot implements IRunnable {
public Robot() {
new Thread(this).Start();
}
private int direction = 0;
private int duration = 0;
private bool go = false;
public void Run() {
DateTime moveStartedAt;
bool moving = false;
while(true) {
if(go) {
if(moving) {
// we are already moving
if((DateTime.Now - moveStartedAt).Seconds >= duration) {
moving = false;
}
} else {
moveStartedAt = DateTime.Now;
moving = true;
}
} else {
moving = false;
}
}
}
public void forward(int direction, int duration) {
this.direction = direction;
this.duration = duration;
this.go = true;
}
public void stop() {
this.go = false;
}
}
(the above code should be modified to be Java for better answer)
What is wrong with this code:
The Run() method consumes one whole Core (it has no sleeps)
Calling stop() and then forward() right away can result in a race condition (the Run() has not seen the stop yet, but you already gave it another forward)
There is no way for Run() to exit
You can call forward() to redirect the move that is already in progress
Others?