I use some menuitems in my application and I have a question about the run method which I override.
private MenuItem menuItemUpdate = new MenuItem("Update", 0, 0) {
public void run() {
// Can I write GUI code here?
}
};
As the comment states, can I write GUI code here? I can`t right? Since I am not on the GUI thread? Should I use the invokeLater-method when I have code that changes the GUI? And what about Dialogs, should they be invoked in invokeLater-methods as well?
And is it necassary to override the run-method of MenuItem if I have made another thread which will be invoked when the user selects the menu item? Could I start that thread in the constructor instead? And leave the run method un-overridden?
You can write UI code there, because the UI thread handles the user's actions, and calls the menu item code. All user interaction is handled by the UI thread.
Yes, you can - because it's on the UI thread, for example:
private MenuItem menuItemUpdate = new MenuItem("Update", 0, 0) {
public void run() {
Show.status("Huzzah!");
}
};
And it seems to be general rule that you don't add any locking around - until you get an IllegalStateException ;-)
Related
My plugin checks if the user is idle for a certain amount of time. With the solution from here, I tried to work my way around. But the eclipse application becomes unresponsive until the loop ends.
Also, the message box is just a plain box with no title and buttons. Can somebody tell me what is wrong with this code?
#Override
public void earlyStartup() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
//while(true) {
for (stop=System.nanoTime()+TimeUnit.MINUTES.toNanos(1);stop>System.nanoTime();) {
Display.getDefault().addFilter(SWT.KeyUp, new Listener() {
#Override
public void handleEvent(Event event) {
stop=System.nanoTime()+TimeUnit.MINUTES.toNanos(1);
System.out.println("checkpoint 1");
}
});
}
Shell shell = new Shell(Display.getDefault());
MessageBox dialog =
new MessageBox(shell, SWT.ICON_INFORMATION | SWT.OK);
dialog.setText("Alert!");
dialog.setMessage("You have been idle for the last 3 minutes.");
shell.open();
stop=System.nanoTime()+TimeUnit.MINUTES.toNanos(1);
System.out.println("checkpoint 2");
}
});
}
Display.asyncExec does not run code in a separate thread. It runs the code in the main UI thread as soon as it is available. The UI thread will be blocked until the code ends.
Instead you can run code in a normal Java thread. But you must call asyncExec to execute any UI code you want to run from the thread.
In your actual code you should only be calling Display.addFilter once. This adds a listener which will be called every time the key up event occurs from then onwards. Since this is UI code you can't actually run this in a background thread at all.
So you can't use a loop like you have shown. You have to keep track of things in the key listener, updating each time the listener is called.
So, I have an activity with a handler.
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
matches = LiveAPI.getMatches();
listAdapter.notifyDataSetChanged();
}
LivePage.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Here I get some data and update my list with it. It works.
When I click on an item of my list, this functon is called
private void showLiveMatch(int position) {
Intent i = new Intent(this, LiveMatch.class);
i.putExtra("match", matches.get(position));
startActivity(i);
}
My new activity appears, wich also contains another handler:
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
match = LiveAPI.getMatch(match.getId());
displayCommentaries();
}
LiveMatch.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Sometimes this works as I want.
But in some cases it seems like in second activity is still called LiveAPI.getMatches() from the first handler rather than LiveAPI.getMatch(match.getId());
Every function displays a console text, and that's how I figure it out what function is called.
Can someone explain me why?
Once you post either m_Runnable (from LivePage or LiveMatch), it does its stuff and then schedules itself to run in 5 seconds. Basically, each time you start one with a click, it creates an infinite loop. Enough clicks and you will have the logic for each of these running constantly. (That is, unless you have some other code that periodically calls mHandler.removeCallbacks(m_Runnable); that you haven't shown us.) Without knowing more about what you're trying to do, it's hard to recommend how to fix this, but you should somehow avoid creating these kind of infinite loops.
Be aware that all handlers you create on the UI thread simply feed Runnable objects into the (single) MessageQueue for the thread. So there's no such thing as something being called from one handler or another.
I have a project that takes time to load everything so I create a splash screen that tells the user through a progressbar how much time it will take to fully load and show the UI, but I'm facing a problem.
When I create my splash, this shows up correctly but then I create and initialize the Principal frame and everything freeze until this has fully load.
So, I try to load my Principal frame in a thread using SwingWorker (and it works) but after unknown NullPointerExceptions and reading a lot I found that this is a terrible idea because I am not creating my UI in the EDT, so here I am stuck.
I know that I must do Swing Calls in the Event Dispatch Thread (EDT) and non-swing heavy work in SwingWorkers but initialize the Swing Components of my Principal Frame are a heavy work too so, what should I do?
I have read some question here, specially this, and I think I get it but I have doubts. Taking that example:
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new SplashScreen();
}
});
// Code to start system (nothing that touches the GUI)
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new MainFrame();
}
});
//.. etc
And reading this site that says:
The Swing framework manages component drawing, updates, and event handlers on the EDT.
Is creating a new component a Swing Call? If it is, What should I do if new MainFrame() will take some time because the project has a lot of components to initialize?
How do I tell the Splash something like "Program loaded 50%"?
What does a Swing Call means and how can I do a correct use of invokeLater and SwingWorker? Maybe the solution is too obvious or have already an answer, but I can't see it and I apologize if this is the case.
Thanks!
You're on a right track. But don't use invokeAndWait (if you have to only) - use invokeLater:
invokeAndWait
Causes doRun.run() to be executed synchronously on the AWT event dispatching thread.
invokeLater
Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread.
Consider that block wrapped doLater is run on EDT thread and code wrapped in doOutside is invoked in another thread (and that's why you don't block the UI):
EDIT:
As pointed out in the comments I add the explanations for the concepts I'll use.
doLater {
// here goes the code
}
is a concept for:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// here goes the code
}
});
And
doOutside {
// here goes the code
}
is a concept for:
new Thread(new Runnable() {
#Override
public void run() {
// here goes the code
}
}).start();
doLater {
final MainFrame m = new MainFrame();
doOutside {
// handle heavy operation
final int result = 1;
doLater {
m.setResult(result);
}
}
}
Conclusion: everything that touches Swing in some way must be run on EDT.
If you want to update percentages:
doLater {
final MainFrame m = new MainFrame();
doOutside {
// handle progress
for(int i = 0; i < someSize; ++i) {
final int progress = i;
doLater {
m.getProgressBar().setProgress(progress);
}
}
}
}
I hope you understand the concept now. The SwingWorker just do exectly something as doOutside === doInBackground & doLater === done/progress
Btw. The code above is a real code: lookup Griffon framework in Groovy.
I have implemented Conway's Game of Life problem in Java swing. Everything is working fine. As you can see in the screenshot below, whenever the "Tick" button is clicked, the game progresses to the next life form. Now, I am planning to include an "Autoplay" button alongside "Tick" button. The purpose of this autoplay is simple. When I hit it, an automated operation should carry on as if I am pressing tick button at an interval of 1 second.
I tried this. But this seems to block all the other operations. How to do this action in a separate thread? A small code snippet would get me going.
class AutoPlayListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btnAutoPlay){
while(true){
Thread.sleep(1000); //InterruptedException try catch hidden
btnTick.doClick();
}
}
}
}
Use a javax.swing.Timer. It will be able to work with the existing ActionListener if the while(true) and Thread.sleep() calls are removed.
As #Ranman said you're blocking main UI thread. I believe SwingUtilities.invokeLater is usually used for things like this.
There are two options:
Start a new thread. The thread will contain the while loop, and execute a method that processes the array. In each iteration, call repaint() or invalidate() on your window to tell it that it needs redrawing.
Use a Timer. The GUI thread will call your routine at regular intervals.
Threads:
In actionPerformed method, create a new Thread. and call its start method.
The Runnable of the thread should run a while loop (as you have already done), and then simply exit.
Timer:
Create an object in your class of type Timer. Use the one in java.swing.Timer if you are using swing (there is also java.util.Timer which isn't good for GUI ops). The timer should have an ActionListener that calls your method once, but the Timer has a repeat rate of 1000ms.
Tips
to invoke the action, you should put it in a separate method, rather than directly under the button handler. That way, you aren't calling GUI stuff from outside the GUI thread.
e.g.
tickButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
doTick();
}
});
The mechanism to stop the thread is equally important! In general, don't use a while(true) in a thread as it will get lost; invent a semaphore to terminate it.
use a JToggleButton rather than Button?
Synchronization:
If you use threads, you will need something like this, to prevent new threads being created each time the button is pressed:
Code
Thread autoplayThread = null;
Object lock;
boolean autoplaying = false;
public void actionPerformed(ActionEvent e){
synchronized(lock){ // prevent any race condition here
if(!autoplaying && autoplayThread==null ){
autoplaying = true;
autoplayThread = new Thread(new Runnable(){
public void run(){
try{
while(autoplaying){ .... }
}finally{
synchronized(lock) {
autoplaying=false;
autoplayThread=null;
}
}
}
});
autoplayThread.start();
}else{ // stop the thread!
autoplaying=false;
}
}
}
I am quite new to Android and Java. Before I was working with C++ where the events where dispatched with messages. Now I would like to create the same user experience for Android platform and I would appreciate any of your suggestions or comments on what is the best way to bind events to user controls.
Here is an example from C++:
ON_MESSAGE(WM_RECORD_START, &CMainFrame::OnRecordStart)//Method OnRecordStarts() executes on WM_RECORD_START_MESSAGE
...
LRESULT CMainFrame::OnRecordStart(WPARAM wParam, LPARAM lParam)
{
m_pNetworkCtrl->SetGeoLocationInfo();
...
}
...
void CMainFrame::RecordStart()
{
PostMessage(WM_RECORD_START);
}
In the case above the method RecordStart() is bound to a Button (it is executed when a Button is pressed) and posts the message WM_RECORD_START. When the message WM_RECORD_START is received, the method OnRecordStart() is executed.
As mentioned before I would like to create a responsive user interface and am not sure if it would be good enough if the method OnRecordStart() is called directly from RecordStart():
void RecordStart()
{
OnRecordStart();
}
I would really appreciate any of your suggestions.
You can emulator the MFC style behavior in Android by using a Handler to post a Runnable into the message queue.
Here is a brief example
class MyClass
{
Handler m_myHandler;
Runnable m_myRunnable;
MyClass()
{
m_myHandler = new Handler();
m_myRunnable = new RUnnable()
{
public void run()
{
// do your stuff here
}
};
}
public void onclickListener(...)
{
// push the runnable into the message queue
m_myHandler.post(m_myRUnnable);
}
}
You have 2 questions here.
How to bind controls. I use
anonymous inner classes everywhere. It is a bit verbose to type in but auto completion makes it a snap.
how to make the UI responsive.
The key is not to do anything time
consuming in the UI thread. If it
takes more than .1s, do the work in
a worker thread and notify the UI to
update when the task is done. The
other thing is to make sure you
don't generate a lot of garbage
since the android GC is pretty primitive right now.
For Buttons I usually extend Button class and override onTouchEvent()
public boolean onTouchEvent (MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
setPressed(true);
}
return super.onTouchEvent(event);
}