Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Contributor
Posts: 14
Registered: ‎06-01-2011
My Device: BlackBerry Q10
My Carrier: Three UK

Push background listening thread with dialog and browser invoke app

Hi All,

 

This has been driving my crazy for a few days now, I have tried everything!

 

This is what I'm trying to acheive;  (Using OS 4.6)

 

- Push messages can be sent to devices, that appear in a dialog

- Device has an icon, which opens the browser on a specific URL (Launcher)

 

Therefore, I have been aiming for having an application that invokes a browser (Simple!) and it has an alternate entry point that runs on startup, that starts a background thread monitoring for push messages. When recieved, the message is displayed in a dialog box.

 

Seems like a faily simple app.. but I cant get it to work. I must admit, I'm not so great with threading, being mainly a web application dev.

 

Problems I have had so far:

Current Version: Freezes BB upon sending a push message

- Cant show Dialog from UI

- When Extending Thread and using Thread.Start.. An 'Egg Timer' permenantly flashing on the BB home Screen.

 

Heres my 'MyApplication.Java' ;

public class MyApplication extends UiApplication {

	private ListeningThread _ListeningThread; 
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		
		boolean startup = false;

	    //Check parameters to see if the application was entered
	    //through the alternate application entry point.
	    for (int i=0; i<args.length; ++i)
	    {
	      if (args[i].startsWith("init")) 
	      {
	        startup = true;
	      }
	    }

	    if (startup)
	    {
	    	MyApplication wm = new MyApplication(); 
			wm.enterEventDispatcher();

	    } else
	    {

			BrowserSession site = Browser.getDefaultSession();
			site.displayPage("https://SomeURL.com");
			site.showBrowser();
			System.exit(0);
	    	
	    }
	}
	
	
	
	private MyApplication() {
		
		_ListeningThread = new ListeningThread();

		invokeAndWait(_ListeningThread);
    	System.out.println("Started Listening Thread XXXXXXXX"); 
    	

	}
	

}

 And Heres my ListeningThread

 

public class ListeningThread implements Runnable {

	// Constants
	// ----------------------------------------------------------------
	private static final String URL = "http://:100"; // PORT 100.
	private static final int CHUNK_SIZE = 256;

	private ListeningThread _listeningThread;

	private boolean _stop = false;
	private StreamConnectionNotifier _notify;

	private synchronized void stop() {
		_stop = true;
		try {
			// Close the connection so the thread will return.
			_notify.close();
		} catch (IOException e) {
			System.err.println(e.toString());
		} catch (NullPointerException e) {
			// The notify object likely failed to open, due to an IOException.
		}
	}

	public void run() {

		StreamConnection stream = null;
		InputStream input = null;
		MDSPushInputStream pushInputStream = null;

		while (!_stop) {
			try {

				// Synchronize here so that we don't end up creating a
				// connection that is never closed.
				synchronized (this) {
					// Open the connection once (or re-open after an
					// IOException), so we don't end up
					// in a race condition, where a push is lost if it comes in
					// before the connection
					// is open again. We open the url with a parameter that
					// indicates that we should
					// always use MDS when attempting to connect.
					_notify = (StreamConnectionNotifier) Connector.open(URL
							+ ";deviceside=false");
				}

				while (!_stop) {

					// NOTE: the following will block until data is received.
					stream = _notify.acceptAndOpen();

					try {
						input = stream.openInputStream();
						pushInputStream = new MDSPushInputStream(
								(HttpServerConnection) stream, input);

						// Extract the data from the input stream.

						DataBuffer db = new DataBuffer();
						byte[] data = new byte[CHUNK_SIZE];
						int chunk = 0;

						while (-1 != (chunk = input.read(data))) {
							db.write(data, 0, chunk);
						}

						updateMessage(data);

						// This method is called to accept the push.
						pushInputStream.accept();

						input.close();
						stream.close();

						data = db.getArray();

					} catch (IOException e1) {
						// A problem occurred with the input stream , however,
						// the original
						// StreamConnectionNotifier is still valid.
						System.err.println(e1.toString());

						if (input != null) {
							try {
								input.close();
							} catch (IOException e2) {
							}
						}

						if (stream != null) {
							try {
								stream.close();
							} catch (IOException e2) {
							}
						}
					}
				}

				_notify.close();
				_notify = null;

			} catch (IOException ioe) {
				// Likely the stream was closed. Catches the exception thrown by
				// _notify.acceptAndOpen() when this program exits.

				if (_notify != null) {
					try {
						_notify.close();
						_notify = null;
					} catch (IOException e) {
					}
				}
			}
		}
	}

	private void updateMessage(final byte[] data) {

		Dialog dialog = new Dialog(Dialog.D_OK, new String(data), Dialog.OK,
				Bitmap.getPredefinedBitmap(Bitmap.EXCLAMATION),
				Manager.VERTICAL_SCROLL);

		synchronized (UiApplication.getEventLock()) {
			Ui.getUiEngine().pushGlobalScreen(dialog, 1, UiEngine.GLOBAL_QUEUE);
		}

	}

}

 

Can anyone offer me ANY advice / solution / information that can help me get this working?

 

Thanks in anticipation

Highlighted
Retired
Posts: 1,561
Registered: ‎04-12-2010
My Device: BlackBerry Z10
My Carrier: Bell

Re: Push background listening thread with dialog and browser invoke app

Hello jhitchcock,

 

The first thing I've noticed is that you are making a call to invokeAndWait() rather than spawning a new Thread for your connection. Though I see that you've noted when you do use a Thread, you get the hourglass constantly displayed.

 

As best practices, when performing any sort of connection or read that is prompted by external events, a Thread would generally be the recommended approach.

 

If you use invokeAndWait(), this will place your Runnable Object on the main event thread and will block until that Runnable completes its execution.

 

This is different from calling Thread.start(), which spawns its own Thread execution and is not related to the main event thread. If you are continously getting an hourglass when spawning a Thread, this generally indicates the garbage collector is performing cleanup, therefore your code should be examined for performance issues.

 

One potential cause could be that _stop is never set to true and your application is being caught in an infinite loop. I am not seeing where in your code that stop() is being invoked and it is a private method, therefore I would expect it occur somewhere in the ListeningThread Class. Your try/catch block also catches an IOException, but does not seem to do anything in that case to stop the looped execution; that could be another potential issue.

 

In summary, to maintain application performance, I would recommend your push listener be placed within its own Thread, rather than a Runnable scheduled to execute on the main event thread. As well, examining your ListeningThread.run() method for deadlock, infinite loops, or unhandled Exceptions to confirm whether it is in fact behaving as expected.

 

Erik Oros

BlackBerry Development Advisor


Erik Oros | @WaterlooErik | eoros@blackberry.com | Developer Issue Tracker

If a reply has answered your question, please click Accept as Solution to help other visitors in the future.