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
Developer
Posts: 176
Registered: ‎11-06-2008
My Device: Not Specified

Tutorial: Communicate between apps/processes

[ Edited ]

A number of people have been messaging me asking for more info on cross app/process communication so here's a sample of what we do at my company. This is a trimmed down demo that shows the minimum needed to get this working.

 

This sample shows how one application has 2 processes. The first process is a background process that is started using an alternate entry point which is set to auto start and be a system module  The second process is the UI process which is started when the user clicks the app's icon. Both the processes implement GlobalEventListener interface so signaling messages can be sent between the 2 processes.

 

The alternate entry point sends the main function a parameter value of "background" while the main icon entry point sends the parameter value "gui".

 

So in the UI of the application let's say the user changes a setting in the application and the background process needs to be informed of the change. To signal the background process from the UI process call this code:

 

 

Utilities.signalApplication(Constants.GUID_MY_APP_SETTINGS_CHANGED, 0, 0, null, null);

 

In this sample code above I did not want to pass any extra values using the int or Object parameters of the GlobalEventListener interface, but you can use them if you like. Or, you can create overloaded versions of the signalApplication and signalUiApplication functions so you don't need to pass dummy values like 0 and null every time.

 

Now if the background process needs to signal the UI process you can do the same thing as above, but use the Utilities.signalUiApplication function instead.

 

It's important that when your UI process is exited that you remove the GlobalEventListener it creates so be sure to call the UiApp's  unregisterGlobalEventListener() function before closing the UI.

 

Below are all the classes needed to set this up. Hopefully this helps everyone who was asking me for help.

 


 

final class Main
{
static void main(String[] args)
{
String launch = null;
if (args != null && args.length > 0)
{
launch = args[0];
}

if (launch != null)
{
if (launch.equals("background"))
{
//start the background process
//this is an auto starting system module entry point
App app = App.getInstance();

app.invokeLater(new Runnable()
{
public void run()
{
ApplicationManager appManager = ApplicationManager
.getApplicationManager();
//sleep until the device is started
while (appManager.inStartup())
{
try
{
Thread.sleep(500);
}
catch (Throwable error)
{
// nothing
}
}
App.getInstance().initialize();
}
});

app.enterEventDispatcher();
}
else if (launcher.equals("gui"))
{
//start the UI process
//this is the main icon entry point
UiApp uiApp = UiApp.getInstance();

uiApp.initialize();

//instantiate the first screen
FirstScreen firstScreen = new FirstScreen();

uiApp.pushScreen(firstScreen);

uiApp.enterEventDispatcher();
}
}
}
}


//this is the background process Application class
final class App extends Application implements GlobalEventListener
{
private static App _instance;

private boolean _initialized = false;

private App()
{
}

static ApplicationDescriptor getApplicationDescriptor()
{
return (Utilities.getApplicationDescriptor("background"));
}

static synchronized App getInstance()
{
if (_instance == null)
{
_instance = new App();
}
return (_instance);
}

public void eventOccurred(long guid, int data0, int data1, Object object0, Object object1)
{
//handle events
if(guid == Constants.GUID_MY_APP_SETTINGS_CHANGED)
{
//handle that the UI process changed the app settings
}
}

void initialize()
{
synchronized (this)
{
if (!_initialized)
{
registerGlobalEventListener();

//do other setup stuff if needed

_initialized = true;
}
}
}

boolean isInitialized()
{
synchronized (this)
{
return (_initialized);
}
}

void registerGlobalEventListener()
{
addGlobalEventListener(this);
}

void unregisterGlobalEventListener()
{
removeGlobalEventListener(this);
}
}


//this is the UI process UiApplication
final class UiApp extends UiApplication implements GlobalEventListener
{
private static UiApp _instance;

private boolean _initialized = false;

private UiApp()
{
}

static ApplicationDescriptor getApplicationDescriptor()
{
return (Utilities.getApplicationDescriptor("gui"));
}

static synchronized UiApp getInstance()
{
if (_instance == null)
{
_instance = new UiApp();
}
return (_instance);
}

public void eventOccurred(long guid, int data0, int data1, Object object0, Object object1)
{
//handle events
}

void initialize()
{
synchronized (this)
{
if (!_initialized)
{
registerGlobalEventListener();

//do other setup stuff if needed

_initialized = true;
}
}
}

boolean isInitialized()
{
synchronized (this)
{
return (_initialized);
}
}

void registerGlobalEventListener()
{
addGlobalEventListener(this);
}

void shutdown()
{
//clean up listeners and shutdown the app
unregisterGlobalEventListener();
System.exit(0);
}

void unregisterGlobalEventListener()
{
removeGlobalEventListener(this);
}
}


//some utility and helper functions
final class Utilities
{
static ApplicationDescriptor getApplicationDescriptor(String launch)
{
if (launch != null)
{
int moduleHandle = CodeModuleManager.getModuleHandle("MyApp");
if (moduleHandle > 0)
{
ApplicationDescriptor[] appDescs = CodeModuleManager.getApplicationDescriptors(moduleHandle);
if (appDescs != null && appDescs.length > 0)
{
//loop over the application descriptors checking for one with the first parameter
//that matches the passed launch parameter
for (int i = appDescs.length - 1 ; i >= 0 ; i--)
{
String[] args = appDescs[i].getArgs();
if (args != null && args.length > 0 && launch.equals(args[0]))
{
return (appDescs[i]);
}
}
}
}
}
return (null);
}

static void postGlobalEventSignal(ApplicationDescriptor appDesc, long guid, int data0, int data1, Object object0, Object object1)
{
if(appDesc != null)
{
int processId = ApplicationManager.getApplicationManager().getProcessId(appDesc);
if (processId > -1)
{
//specifically send it to the process ID for the given app descriptor
ApplicationManager.getApplicationManager().postGlobalEvent(processId, guid, data0, data1, object0, object1);
}
else
{
//couldn't get the process ID so fall back and send a global event to the whole system
ApplicationManager.getApplicationManager().postGlobalEvent(guid, data0, data1, object0, object1);
}
}
}

//send a global event to the background process
static void signalApplication(long guid, int data0, int data1, Object object0, Object object1)
{
postGlobalEventSignal(App.getApplicationDescriptor(), processId, guid, data0, data1, object0, object1);
}

//send a global event to the UI process
static void signalUiApplication(long guid, int data0, int data1, Object object0, Object object1)
{
postGlobalEventSignal(UiApp.getApplicationDescriptor(), processId, guid, data0, data1, object0, object1);
}
}


// constants
final class Constants
{
//this is a long value of
//com.mycompany.myapp.Constants.GUID_MY_APP_SETTINGS_CHANGED
static final long GUID_MY_APP_SETTINGS_CHANGED = 0xb51cc430376d808dL;
}

 

 

 

Message Edited by jhw1701 on 08-05-2009 06:29 AM
Developer
Posts: 1,807
Registered: ‎04-28-2009
My Device: Z10 (STL100-4)-10.3.2.858, Z10 (STL100-3)-10.3.1.2576, Z30 (STA100-5)-10.3.1.2582, Passport (SQW100-1)-10.3.1.2576, PlayBook (16GB)-2.1.0.1917
My Carrier: Verizon

Re: Tutorial: Communicate between apps/processes

I learn something new every day. Good little tutorial.
---Spends time in #blackberrydev on freenode (IRC)----
Three simple rules:
1. Please use the search bar before making new posts.
2. "Like" posts that you find helpful.
3. If a solution has been found for your post, mark it as solved.
--I code too much. Well, too bad.
New Developer
Posts: 13
Registered: ‎11-02-2009
My Device: Not Specified

Re: Tutorial: Communicate between apps/processes

[ Edited ]

Thank you for the useful tutorial.

One question tho.

 

How and where would you use this code?

 

Utilities.signalApplication(Constants.GUID_MY_APP_SETTINGS_CHANGED, 0, 0, null, null);

Since UiApp class is never instantiated when starting up as background process, I'm getting an error saying "application already running"

 

In other words, how would you start up the UiApp application from background module using this structure.?

 

Thanks in advance for the advice

Developer
Posts: 176
Registered: ‎11-06-2008
My Device: Not Specified

Re: Tutorial: Communicate between apps/processes

This tutorial has nothing to do with starting one process from another.

 

But to do that find the application descriptor you want to start and pass it to ApplicationManager's runApplication function.

 

ApplicationDescriptor appDesc = Utilities.getApplicationDescriptor("gui");
if(appDesc != null)
{
ApplicationManager appManager = ApplicationManager.getApplicationManager();
int appProcessId = appManager.getProcessId(appDesc);
if (appProcessId == -1)
{
try
{
appManager.runApplication(appDesc);
}
catch(Exception ex)
{
// log error
}
}
}
Visitor
Posts: 1
Registered: ‎06-19-2010
My Device: Tour 9630
My Carrier: Megafon

Re: Tutorial: Communicate between apps/processes

Some fixes:

In Main.main():

--- else if (launcher.equals("gui"))
+++ else if (launch.equals("gui"))

 In Utilities.signalUiApplication():

--- postGlobalEventSignal(UiApp.getApplicationDescriptor(), processId, guid, data0, data1, object0, object1);
+++ postGlobalEventSignal(UiApp.getApplicationDescriptor(), guid, data0, data1, object0, object1);

 And thank you very much! Very helpful!

Developer
Posts: 176
Registered: ‎11-06-2008
My Device: Not Specified

Re: Tutorial: Communicate between apps/processes

Indeed, nice catches, thank you. That's what I get for editing and trimming down the real code on the fly. The revised full code is below.

 

final class Main
{
static void main(String[] args)
{
String launch = null;
if (args != null && args.length > 0)
{
launch = args[0];
}

if (launch != null)
{
if (launch.equals("background"))
{
//start the background process
//this is an auto starting system module entry point
App app = App.getInstance();

app.invokeLater(new Runnable()
{
public void run()
{
ApplicationManager appManager = ApplicationManager
.getApplicationManager();
//sleep until the device is started
while (appManager.inStartup())
{
try
{
Thread.sleep(500);
}
catch (Throwable error)
{
// nothing
}
}
App.getInstance().initialize();
}
});

app.enterEventDispatcher();
}
else if (launch.equals("gui"))
{
//start the UI process
//this is the main icon entry point
UiApp uiApp = UiApp.getInstance();

uiApp.initialize();

//instantiate the first screen
FirstScreen firstScreen = new FirstScreen();

uiApp.pushScreen(firstScreen);

uiApp.enterEventDispatcher();
}
}
}
}


//this is the background process Application class
final class App extends Application implements GlobalEventListener
{
private static App _instance;

private boolean _initialized = false;

private App()
{
}

static ApplicationDescriptor getApplicationDescriptor()
{
return (Utilities.getApplicationDescriptor("background")) ;
}

static synchronized App getInstance()
{
if (_instance == null)
{
_instance = new App();
}
return (_instance);
}

public void eventOccurred(long guid, int data0, int data1, Object object0, Object object1)
{
//handle events
if(guid == Constants.GUID_MY_APP_SETTINGS_CHANGED)
{
//handle that the UI process changed the app settings
}
}

void initialize()
{
synchronized (this)
{
if (!_initialized)
{
registerGlobalEventListener();

//do other setup stuff if needed

_initialized = true;
}
}
}

boolean isInitialized()
{
synchronized (this)
{
return (_initialized);
}
}

void registerGlobalEventListener()
{
addGlobalEventListener(this);
}

void unregisterGlobalEventListener()
{
removeGlobalEventListener(this);
}
}


//this is the UI process UiApplication
final class UiApp extends UiApplication implements GlobalEventListener
{
private static UiApp _instance;

private boolean _initialized = false;

private UiApp()
{
}

static ApplicationDescriptor getApplicationDescriptor()
{
return (Utilities.getApplicationDescriptor("gui"));
}

static synchronized UiApp getInstance()
{
if (_instance == null)
{
_instance = new UiApp();
}
return (_instance);
}

public void eventOccurred(long guid, int data0, int data1, Object object0, Object object1)
{
//handle events
}

void initialize()
{
synchronized (this)
{
if (!_initialized)
{
registerGlobalEventListener();

//do other setup stuff if needed

_initialized = true;
}
}
}

boolean isInitialized()
{
synchronized (this)
{
return (_initialized);
}
}

void registerGlobalEventListener()
{
addGlobalEventListener(this);
}

void shutdown()
{
//clean up listeners and shutdown the app
unregisterGlobalEventListener();
System.exit(0);
}

void unregisterGlobalEventListener()
{
removeGlobalEventListener(this);
}
}


//some utility and helper functions
final class Utilities
{
static ApplicationDescriptor getApplicationDescriptor(String launch)
{
if (launch != null)
{
int moduleHandle = CodeModuleManager.getModuleHandle("MyApp");
if (moduleHandle > 0)
{
ApplicationDescriptor[] appDescs = CodeModuleManager.getApplicationDescriptors(module Handle);
if (appDescs != null && appDescs.length > 0)
{
//loop over the application descriptors checking for one with the first parameter
//that matches the passed launch parameter
for (int i = appDescs.length - 1 ; i >= 0 ; i--)
{
String[] args = appDescs[i].getArgs();
if (args != null && args.length > 0 && launch.equals(args[0]))
{
return (appDescs[i]);
}
}
}
}
}
return (null);
}

static void postGlobalEventSignal(ApplicationDescriptor appDesc, long guid, int data0, int data1, Object object0, Object object1)
{
if(appDesc != null)
{
int processId = ApplicationManager.getApplicationManager().getProc essId(appDesc);
if (processId > -1)
{
//specifically send it to the process ID for the given app descriptor
ApplicationManager.getApplicationManager().postGlobalEvent(processId, guid, data0, data1, object0, object1);
}
else
{
//couldn't get the process ID so fall back and send a global event to the whole system
ApplicationManager.getApplicationManager().postGlobalEvent(guid, data0, data1, object0, object1);
}
}
}

//send a global event to the background process
static void signalApplication(long guid, int data0, int data1, Object object0, Object object1)
{
postGlobalEventSignal(App.getApplicationDescriptor(), guid, data0, data1, object0, object1);
}

//send a global event to the UI process
static void signalUiApplication(long guid, int data0, int data1, Object object0, Object object1)
{
postGlobalEventSignal(UiApp.getApplicationDescriptor(), guid, data0, data1, object0, object1);
}
}


// constants
final class Constants
{
//this is a long value of
//com.mycompany.myapp.Constants.GUID_MY_APP_SETTINGS_CHANGED
static final long GUID_MY_APP_SETTINGS_CHANGED = 0xb51cc430376d808dL;
}
Highlighted
Contributor
Posts: 14
Registered: ‎06-19-2011
My Device: simulator Torch 9800
My Carrier: wired

Re: Tutorial: Communicate between apps/processes

Allright man, this is good stuff, especially obtaining an ApplicationDescriptor, but I am fed up with searching for the proper way to get a valid guid.

I mean come on!

static final long GUID_MY_APP_SETTINGS_CHANGED = 0xb51cc430376d808dL;

is that supposed to be globally unique ??

thanks Smiley Happy