08-22-2011 08:05 PM
I am trying to update a screen (that extends MainScreen) with data that is changing based on a continuously running thread which calls a Web Service over http.
I was trying to use the Observer/Observable pattern based off an example I found online, but this was in reference to a popup and I’m not exactly how to complete this for the screen I have. Below is an edited down version of the code I am working with – I know I need to tie in the instanceOf the observable piece, but not sure how with this existing code that I have to maintain "as-is"...
public interface WebServiceStatusObserver
{
public void update(String currentStatus);
}
public interface WebServiceStatusObservable
{
public void setWebServiceStatusObserver(WebServiceStatusObserv er observer);
}
public class MyScreen extends MainScreen, implements WebServiceStatusObserver
{
LabelField latestWsStatus; // label to be updated
WebServiceThread wsThread = null; // background thread updates from web servece
public MyScreen()
{
latestWsStatus = new LabelField("");
HorizontalFieldManager hfmTitle = new HorizontalFieldManager
(Manager.USE_ALL_WIDTH | NO_HORIZONTAL_SCROLL)
{
hfmTitle.add(latestWsStatus);
}
}
public void update(String currentStatus)
{
final String finalCurrentStatus = currentStatus;
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
latestWsStatus.setText(finalCurrentStatus);
}
});
}
class WebServiceThread extends Thread implements Runnable, WebServiceStatusObservable
{
boolean quit = false;
private WebServiceStatusObserver observer;
public void setWebServiceStatusObserver(WebServiceStatusObserv er observer)
{
this.observer = observer;
}
public void run()
{
if ( observer != null ) { observer.update("Starting"); }
while(true)
{
if ( observer != null ) { observer.update("Running”); }
// <some call to a web service over http goes here>
Thread.sleep(10000);
}
}
}
}
Solved! Go to Solution.
08-23-2011 03:27 AM
The code that you have supplied looks OK as is and should work for your MainScreen. Your observer's 'update()' method correctly does the update on the Event Thread by using invokeLater.
One reason why people will often put this in a separate PopupScreen is that they use this screen to 'block' UI interaction while the Screen is waiting for the network connection. In this case, your MainScreen may have to have some special processing when the connection is in action to stop the user moving off the screen or to stop the network activity if the user does.
08-23-2011 03:32 AM - edited 08-23-2011 03:49 AM
All is looking fine. Just add these lines to Screen constructor:
wsThread = new WebServiceThread(); wsThread.setWebServiceStatusObserver(this);
And in uiEungineAttached start the web thread:
wsThread.start();
No needs to any instanceof operators.
Regards,
Eugen
08-23-2011 02:57 PM - edited 08-23-2011 03:02 PM
Thanks Eugen, but I am getting a compile error. I realized that in my edited example I left an important part of the code which already has the weThread instantiated and starting so I have included just the screen constructor code below.
You can see where I had added the one missing line (marked with **) along with the compile error message as a comment:
public MyScreen()
{
latestWsStatus = new LabelField("");
wsThread = new WebServiceThread();
wsThread.setWebServiceStatusObserver(this);
HorizontalFieldManager hfmTitle = new HorizontalFieldManager
(Manager.USE_ALL_WIDTH | NO_HORIZONTAL_SCROLL)
{
hfmTitle.add(latestWsStatus);
}
myButton = new BitmapField(ScaledButtonOn, BitmapField.FOCUSABLE | ButtonField.CONSUME_CLICK)
{
boolean bFocus = false;
protected boolean buttonClick(int status, int time)
{
UiApplication.getUiApplication().invokeLater
(new Runnable()
{
public void run()
{
UiApplication uiapp = UiApplication.getUiApplication();
wsThread = new WebServiceThread(myButton);
wsThread.start();
wsThread.setWebServiceStatusObserver(this); // COMPILE ERROR**
//** this method in the type MyScreen.wsThread is not applicable
//** for the arguments (new Runnable(){})
}
});
}
}
ERROR**
The method setWebServiceStatusObserver(WebServiceStatusObserv
08-23-2011 05:53 PM - edited 08-23-2011 05:54 PM
Thanks peter_strange for your input -- indeed I based a lot of what I needed on your example, which was very helpful:
However, I need the updates from the thread to go to the main screen rather than a popup, for a few reasons:
Are there any good examples of a main screen being updated by a background thread out there? It seems like a basic scenario that would be behind most business scenarios of this nature.
08-23-2011 05:53 PM
Replace this:
protected boolean buttonClick(int status, int time)
{
UiApplication.getUiApplication().invokeLater
(new Runnable()
{
public void run()
{
UiApplication uiapp = UiApplication.getUiApplication();
wsThread = new WebServiceThread(myButton);
wsThread.start();
wsThread.setWebServiceStatusObserver(this); // COMPILE ERROR**
//** this method in the type MyScreen.wsThread is not applicable
//** for the arguments (new Runnable(){})
}
});
}
with this
protected boolean buttonClick(int status, int time)
{
wsThread = new WebServiceThread(myButton);
wsThread.setWebServiceStatusObserver(this);
wsThread.start();
}
I suspect it will work.
08-23-2011 06:08 PM
Thanks again peter_strange but I am now getting a different compile error -- probably because that buttonCllick code is encapsulated within a BitmapField button (see "MyButton" in my code sample).
The error I am getting is complaining about the input parameter to my function, because it is seeing "this" as the BitmapField I guess.
I suspect we are getting close but I'm afraid I'm still not sure how to handle this situation. If there's a way to make it work without having to tear up too much other "indirectly related" code that would be great...
08-23-2011 07:12 PM
try replacing
wsThread.setWebServiceStatusObserver(this);
with
wsThread.setWebServiceStatusObserver(MyScreen.this
08-23-2011 08:14 PM