I'm working on a J2ME Bluetooth application, and one of the classes searches for other Bluetooth devices. It does this in another thread, so the GUI doesn't freeze up.
The problem I have is how to pass messages to the thread. I can ask it to search, or cancel searching, and it can tell the GUI it has found some other devices. Currently I use notify and wait, but that seems like a hack. What I really want is some way of calling notify with a parameter, for example what I want it to do. Is there any way to do this?
The general approach to this kind of situation must be as follows:
Decouple the remote source of the data with the "View".
Make sure that the view is capable of updating dynamically when the underlying data changes. J2ME components do this by default - but if you author your own components, then you must take this into consideration.
Run a separate thread and retrieve data.
Notify the view whenever the data arrives.
The working code for the MIDlet is posted below
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.*;
public class AsyncUI extends MIDlet implements SearchListener, CommandListener{
Command CANCEL = new Command("STOP SEARCH",Command.CANCEL,1);
Command EXIT = new Command("EXIT",Command.EXIT,2);
SearchDevices finder = new SearchDevices();
List deviceList = new List("List of Devices",List.IMPLICIT);
public void startApp() {
Display d = Display.getDisplay(this);
finder.setSearchListener(this);
deviceList.addCommand(CANCEL);
deviceList.addCommand(EXIT);
deviceList.setCommandListener(this);
d.setCurrent(deviceList);
new Thread( finder).start();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void found( Device d){
deviceList.append(d.getName(), null);
}
public void commandAction( Command c, Displayable d){
if( c == CANCEL){
finder.cancel();
deviceList.removeCommand(CANCEL);
}else if( c== EXIT ){
finder.cancel(); /* Cleanup all resources before you quit*/
notifyDestroyed();
}
}
}
class SearchDevices implements Runnable{
private boolean keepFinding=true;
private static final int LONG_TIME=10000; /* 10 Seconds */
SearchListener l =null; /* Currently only one listener. There could be many*/
public void run(){
int i =0;
System.out.println(" -- Started the activity of finding --");
while( keepFinding){
try {
Thread.currentThread().sleep(LONG_TIME);
Device d = new Device("Device Found "+i);
i++;
System.out.println(" -- Found the device --");
l.found(d);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.println(" -- No more devices will be found --");
}
public void cancel(){ keepFinding = false; }
public void setSearchListener( SearchListener l){this.l=l;}
}
class Device{
String name;
public Device(String name ){ this.name = name; }
public String getName(){ return name ; }
}
interface SearchListener{
public void found( Device device);
}
You'll have to implement you're own blocking queue, this is actually a producer-consumer problem. Once you have a blocking queue, you can then easily wrap pushes to the queue in their own methods, making it feel like you're doing asynchronous calls to the worker thread.
Related
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?
So I'm having problems with my threads in an Android project. I have a ThreadStarter class, with a BuildScreen() function, which actually creates the layout for each activity. The only problem is, sometimes the threads just won't start, and I have no idea why. They work like 98% of the time though, but when they don't, the current activity will never get initalized, and the user has to restart the app, which is inconvenient.
Here is a snippet of my code:
public class ThreadStarter
{
public static void BuildScreen()
{
try
{
GlobalVariables.screenDrawer.onStart();
GlobalVariables.listInitaliser.onStart();
Logger.log("ThreadStarter.BuildScreen", "Threads started");
}
catch(IllegalThreadStateException e)
{
GlobalVariables.screenDrawer.StopThread();
GlobalVariables.listInitaliser.StopThread();
Logger.log("ThreadStarter.BuildScreen", "Threads stopped");
GlobalVariables.screenDrawer.onStart();
GlobalVariables.listInitaliser.onStart();
}
catch(Exception e)
{
Logger.Error("Couldn't stop or start the threads!");
Logger.Error("Exception () Message: " + e.getMessage());
}
}
}
The threads:
public class ListInitialiser extends Thread
{
private static ListInitialiser _thread;
public synchronized void run()
{
GlobalVariables.CurrentActivity.UpdateLists();
}
public void onStart()
{
_thread = new ListInitialiser();
_thread.start();
}
public void StopThread()
{
if (_thread != null)
{
_thread.interrupt();
_thread = null;
}
}
}
I won't insert the ScreenDrawer thread here, because it's pretty much the same, except it calls another function.
And this is how every activity is created (of course the contentView differs in each file):
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getWindow().getAttributes().windowAnimations = R.style.Fade;
setContentView(R.layout.activity_fine_data_3);
GlobalVariables.CurrentActivity = this;
ThreadStarter.BuildScreen();
Logger.log("INFORMATION", "Person3DataActivity (Information 3/5)");
}
In the GlobalVariables section I have these variables:
public static ScreenDrawer screenDrawer = new ScreenDrawer();
public static ListInitialiser listInitaliser = new ListInitialiser();
If anyone has a solution or and idea, please share it with me.
Thanks in advance.
EDIT: Okay, so I took onof's (rather harsh but useful :)) advice, and refactored my code to use AsyncTask instead. It seems to be working pretty fine. I managed to implement it into my AbstractActivity class, which is the parent of every Activity I use, and now all I have to do is call BuildScreen() method in every onCreate method.
Thanks for the replies everyone.
try to add this to your class where u declared Global Variables
private static ListInitialiser instance;
public static synchronized ListInitialiser getInstance() {
if (instance == null)
instance = new ListInitialiser();
return instance;
}
Everytime you donot have to create new when u r taking static.I dont know but may be this can help
You can't rely on static variables as everything that is static (non final) in Android can be cleared any time the system need memory. So don't think static = storage.
You should instead instantiate the objects when you need them, like following:
public static ScreenDrawer getScreenDrawer() {
return new ScreenDrawer();
}
public static ListInitialiser getListInitialiser () {
return new ListInitialiser ();
}
probability this question have been asked before but i cant find anything in my searching mechanism. I am trying to create a multiple threads, in an array list but i want to retrieve them from an arraylist and filter them by the attribute of w1 i used in my code. any ideas ?
w1 = new FirstWorker(ProductsList, OrdersList, s);
FirstWorkerThread = new Thread(w1);
ThreadArrayList.add(FirstWorkerThread);
//I know i cant do the code below but i want to do that how ?
for(Thread x : ThreadArrayList){
x.ProductsList
}
this is FirstWorker class
import java.lang.String;
import java.util.HashMap;
/*
* To change this template, choose Tools | Templates and open the template in
* the editor.
*/
/**
*
* #author Dimitris
*/
public class FirstWorker extends Thread implements Runnable {
private OrderList orderlist;
private ProductList productlist;
private String Worker;
boolean Stop;
private int speed = 1000;
public FirstWorker(ProductList productlist, OrderList orderlist, String Worker) {
this.productlist = productlist;
this.orderlist = orderlist;
this.Worker = Worker;
this.Stop = true;
}
public void run() {
if (Stop == true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
while (orderlist.returnLengthofOrder() != 0) {
if (Thread.interrupted()) {
System.out.println("I am in the thread inturrupt");
// We've been interrupted: no more crunching.
return;
}
if (orderlist.getDone() == true) {
} else if (orderlist.getDone() == false) {
orderlist.setDoneTrue();
orderlist.Purchased(Worker);
orderlist.setDoneFalse();
try {
Thread.sleep(this.speed);
} catch (InterruptedException e) {
return;
}
}
}
}
}
public void setWork() {
Stop = false;
}
public void setSpeed(int speed) {
this.speed = speed;
}
}
If you want to access a member variable of your Runnable, you should extend Thread instead of implementing Runnable. Also, don't extend Thread AND implement Runnable. Pick one.
public class MyThread extends Thread
{
public int myarg;
public void run()
{
}
}
public void useThread(int inputArgs[])
{
ArrayList<MyThread> threadArray = new ArrayList<MyThread>();
for (int arg : inputArgs)
{
MyThread temp = new MyThread(arg);
temp.start();
threadArray.add(temp);
}
for (MyThread t : threadArray)
System.out.println(t.myarg);
}
The simple answer with constructing a Thread with a Runnable is no.
The constructor for Thread that you are using accepts a Runnable ... I assume that FirstWorker implements the Runnable interface.
But looking at the API docs for Thread http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html there is no method to return the Runnable.
Without knowing more context about what your trying to do, the simplest approach might be to change FirstWorker to extend Thread then the loop you have would work.
That would probably work, but would need to know more about what your doing to reccomend anything else.
If you want to retrieve properties from the Runnable instance within a Thread object, I do not believe that is generally possible, since the Thread class does not have a method to return its target Runnable object.
That said, you can always extend the Thread class itself, which would allow you to use instanceof with the Thread instances themselves before casting and getting to whatever property you need.
Keep in mind, though, that extending Thread is not a recommended practice and if you are intending to get the result of some computation straight from the Runnable object, you could run into some severe trouble if you are not careful.
In any case, recent Java versions (i.e. 1.5+) offer substantial capabilities for concurrency and I suspect that your application would benefit from a re-design that uses them.
We might be able to help more if you explained what exactly you are trying to do in broader terms...
You should consider using the new java.util.concurrent package. What you are trying to do can be implemented a lot easier and intuitively with an ExecutorService and a collection of Callables.
Check out this sample and the Executors API (specifically the fixedThreadPool).
I am trying to make an application in Java.
To make Swing work correctly, I did this:
public static void main(String[] array){
String outerInput;
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
// I want this string input.
String input = JOptionPane.showInputDialog(
null,"Stop ?", JOptionPane.QUESTION_MESSAGE);
});
// How can I get this input value in String outerInput?
}
How would I get this input string in my main body?
You can use AtomicReference<String> for passing values between threads in a thread-safe manner.
As noted by Hemal, you'll need some synchronization between two threads to make sure it was already executed. For example, you can use CountDownLatch or use SwingUtilities.invokeAndWait (make sure you don't call it from Swing thread!)
Update: here is the complete example using AtomicReference and CountDownLatch
public class Main {
public static void main(String[] args) throws InterruptedException {
final AtomicReference<String> result = new AtomicReference<String>();
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String input = JOptionPane.showInputDialog(null, "Stop?", "Stop?", JOptionPane.QUESTION_MESSAGE);
result.set(input);
// Signal main thread that we're done and result is set.
// Note that this doesn't block. We never call blocking methods
// from Swing Thread!
latch.countDown();
}
});
// Here we need to wait until result is set. For demonstration purposes,
// we use latch in this code. Using SwingUtilities.invokeAndWait() would
// be slightly better in this case.
latch.await();
System.out.println(result.get());
}
}
Also read this answer about general design of GUI (and Swing) applications.
How would I get this input string in my main body?
You wouldn't. The idea that your "main" would invoke a Swing dialog box and then do something with the results is contrary to the entire idea of a graphical user interface.
In a GUI, you design your program to deal with a series of user-initiated events. Those events may be completely asynchronous, such as the keystrokes, selection, and menu choices of your typical word processor. Or they may be scripted, such as the question-answer format of a "wizard."
Assuming that you want to do something like the latter, you would implement it using the following sequence:
The user initiates some action, perhaps selecting a menu choice. This is turned into an invocation of an ActionListener, which decides that it needs more input from the user.
The ActionListener, which is executed on the event dispatch thread, is permitted to do anything that it wants to the UI, such as displaying a dialog. That dialog may be modal or non-modal; in one case the output is available to the original listener, in the other you need to write a new listener to take subsequent action.
Once you have enough information, you may choose to invoke a background operation. You would typically have a thread-pool to service these requests. You would not attempt to perform the request on the "main" thread; in fact, for all intents the main thread is no longer running.
When your operation completes running, it would push data back to the event dispatch thread using SwingUtilities.invokeLater(). While you could use invokeAndWait() to send results to Swing in the middle of your background operation, that's rarely a good idea. Instead, create a sequence of operations, preferably one that is easily canceled by the user.
The "standard" way to initiate operations on a background thread is via SwingWorker. There are alternatives; for example, you could use a BlockingQueue to send operations to a single long-running background thread, and use invokeLater() to return the results.
Regardless, there's one rule that you do not want to break: never, ever, perform a blocking operation on the event dispatch thread. If you do that, then your application is broken.
Right now you have two threads going: the main thread and the EDT (event dispatch thread). I assume you know that SwingUtilities.invokeLater(runnable) is running a task on the EDT.
To share data between threads, you just need some variable that is in the scope of both threads. The easiest way to accomplish that is to declare a volatile data member or AtomicReference in the class containing the main method.
In order to ensure that you read the value after it is returned by the JOptionPane, the simplest thing you can do here is to change the invokeLater call to an invokeAndWait call. This will cause your main thread to stop executing until what you have put onto the EDT has completed.
Ex:
public class MyClass {
private static volatile String mySharedData;
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
mySharedData = JOptionPane.showInputDialog(null, "Stop ?", JOptionPane.QUESTION_MESSAGE);
}
});
// main thread is blocked, waiting for the runnable to complete.
System.out.println(mySharedData);
}
}
If your main thread is executing some task that shouldn't be stopped while the option pane is present, then in the main thread you can periodically check (i.e., in the outer part of the loop that is running your task) whether or not mySharedData has been set. If your task doesn't loop and is instead doing some I/O or waiting, you can make use of Thread.interrupt and check mySharedData in the InterruptedExecption handlers.
I suggest using the observer/observable pattern for this, perhaps with a PropertyChangeListener. Then your Swing app will be able to notify any and all listeners if the critical variable(s) state changes.
For example:
import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
public class ListenToSwing {
public static final String STATE = "state";
private static final int STATE_MAX = 10;
private static final int STATE_MIN = -10;
private JPanel mainPanel = new JPanel();
private int state = 0;
private JSlider slider = new JSlider(STATE_MIN, STATE_MAX, 0);
public ListenToSwing() {
mainPanel.add(slider);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setMajorTickSpacing(5);
slider.setMinorTickSpacing(1);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
setState(slider.getValue());
}
});
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
mainPanel.addPropertyChangeListener(listener);
}
public Component getMainPanel() {
return mainPanel;
}
public void setState(int state) {
if (state > STATE_MAX || state < STATE_MIN) {
throw new IllegalArgumentException("state: " + state);
}
int oldState = this.state;
this.state = state;
mainPanel.firePropertyChange(STATE, oldState, this.state);
}
public int getState() {
return state;
}
public static void main(String[] args) {
final ListenToSwing listenToSwing = new ListenToSwing();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("ListenToSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(listenToSwing.getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
listenToSwing.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(ListenToSwing.STATE)) {
System.out.println("New state: " + listenToSwing.getState());
}
}
});
}
}
You can use an AtomicReference and invokeAndWait.
public static void main(String[] array){
AtomicReference<String> outerInput = new AtomicReference<String>();
SwingUtilities.invokeAndWait(new Runnable(){
#Override
public void run() {
String input = JOptionPane.showInputDialog(
null,"Stop ?", JOptionPane.QUESTION_MESSAGE);
outerInput.set(input);
});
outerInput.get(); //Here input is returned.
}
You can trivially expose it to the outer class by declaring a String[] in which the runnable sets the value. But note that you will need some synchronization mechanism to know whether it has been assigned by the Runnable.
The following code will do what you want. I have done something similar except I was launching a JFileChooser instead of an input dialog. I found it more convenient than hard coding a bunch of paths into my application or accepting a command line argument, at least for testing purposes. I would like to add that one could modify the prompt() method to return the FutureTask instance for added flexibility.
public class Question {
public static void main(String[] args) {
Question question = new Question();
String message = "Stop?";
System.out.println(message);
// blocks until input dialog returns
String answer = question.ask(message);
System.out.println(answer);
}
public Question() {
}
public String ask(String message) {
try {
return new Prompt(message).prompt();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
private class Prompt implements Callable<String> {
private final String message;
public Prompt(String message) {
this.message = message;
}
/**
* This will be called from the Event Dispatch Thread a.k.a. the Swing
* Thread.
*/
#Override
public String call() throws Exception {
return JOptionPane.showInputDialog(message);
}
public String prompt() throws InterruptedException, ExecutionException {
FutureTask<String> task = new FutureTask<>(this);
SwingUtilities.invokeLater(task);
return task.get();
}
}
}
I'm in the midst of porting a C# program over to Java that makes heavy use of delegates and the delegate's BeginInvoke method to notify of an event asynchronously. Take a data communication thread for example. It might have to notify another worker thread of its state as well as the GUI.
It seems to me that the best way to notify of the various events for different classes is to have an IClassNameHereWatcher interface that defines all of the types of events that the class "publishing" the event would need to notify about and then each class that needs to listen would implement this interface and register itself as a listener. The thing I'm not quite sure about is how to make this asynchronous. Here's approximately what I'm referring to:
public interface IFrobWatcher {
void frobDidSomething();
void frobReceivedData(object data);
}
public class Frob implements Runnable {
List<IFrobWatcher> watchers = new ArrayList<IFrobWatcher>();
private void run() {
while (true) {
// Long running task
if (blah) notifyWeDidSomething();
notifyOfData(someDataObject);
}
}
public void addWatcher(IFrobWatcher watcher) {
watchers.Add(watcher);
}
private void notifyWeDidSomething() {
for (IFrobWatcher watcher : watchers) {
watcher.frobDidSomething(); // How do I make this asynchronous?
}
}
private void notifyOfData(object someDataObject) {
for (IFrobWatcher watcher : watchers) {
watcher.frobReceivedData(someDataObject); // How do I make this asynchronous?
}
}
}
public class FrobWatcher implements IFrobWatcher {
private Frob frobToWatch;
public FrobWatcher(Frob frob) {
frobToWatch = frob;
frobToWatch.addListener(this);
}
public void FrobDidSomething() {
System.out.println("Frob did something!");
}
public void FrobReceivedData(object received) {
System.out.println("Frob received: " + received.ToString());
}
public static void main(string[] args) {
Frob f = new Frob();
FrobWatcher fw = new FrobWatcher(f);
(new Thread(f)).start();
}
}
And this is a fairly simplified example, but hopefully it conveys what I'm looking for. If something isn't clear or doesn't make sense, please comment and I'll try to clarify or fix the example.
I would recommend an Executor from the java.util.concurrent package.
This is how asynchronous callbacks are handled in the Raptor framework:
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(
filesPoller, 0 /*initial delay*/,
checkInterval,
TimeUnit.MILLISECONDS
);
NB. this scheduling is recurring.