I am sending an object called event inside my application but to another process.
I am using IPC EventBus. When I register I cannot receive events back.
This is what I am doing:
public class UserActivity extends Activity
implements IIpcEventBusConnectionListener, IIpcEventBusObserver {
#Override
public void onConnected(IIpcEventBusConnector connector) {
connector.registerObserver(this);
}
...
}
How can I receive the events?
Are you calling conn.startConnection();? If you don't then it will not work.
IIpcEventBusConnector conn =
ConnectorFactory.getInstance().buildConnector(context, this, "com.myapp");
conn.startConnection();
Related
I have a set of subscribers that need to start when server starts up.
Right now I'm instantiating them and calling run method on them in Application.java.
Was thinking it would be wonderful if these get instantiated on their own, may be using custom annotation or by belonging to an interface (get all classes of interface and instantiate). This way anyone writing a new subscriber in future doesn't need to create the object and call run() on it.
Wondering if anyone has solved it earlier and whether it makes sense to do it.
Example:
I have an interface for event handlers:
interface EventHandler {
void process(String data);
}
And then implementation classes:
public class CoolEventHandler implements EventHandler {
public void process(String data) {
//handle cool event
}
}
public class HotEventHandler implements EventHandler {
public void process(String data) {
//handle hot event
}
}
And I have a subscriber service which listens to remote APIs and if there's data, it passes that to handler:
public class PollService {
public static void register(String API, EventHandler eventHandler) {
//create a thread to poll API
//and if data is received, call eventHandler.process()
}
}
At the start of my application I'm registering handlers in Application.java
PollService.register("/cool", new CoolEventHandler());
PollService.register("/hot", new HotEventHandler());
Tomorrow if there's a new handler, say WarmEventHandler, I'll have to call register again. I'm trying to avoid this last step. What would be the best way to register all classes of EventHandler?
you may know about Google Cloud Messaging
The problem is that when a gcm message triggers by the server, my application receives a bundle from google play services, this happen at GcmBroadcastReceiver.java. Here i can send this data to other classes in order to append some info from the server.. well. I got stuck when i try to update, for example, some views in the UI thread.
HOW I CAN DO THIS?
Imagine that MainActivity.java is the UI thread when i declare the views, etc.
I tried to create here a public static method which can be called directly by GcmBroadcastReceiver.java by this way: MainActivity.*updateUI*(args..), but it throws this exception:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Can anyone try to explain me this? i also know about asyncTask but i cant imagine how it works. I also find some pages explaining events that are fired by the UI thread it self like runnables that do some task in background. Im searching something like this:
MainActivity extends Activity{
...
protected void onCreate(Bundle blabla)..{
setContentView(R.layout.blabla);
registerSomeEvent(this);
}
private void handleEvent(Bundle ...){
... do stuff with the data provided in the UI thread
}
}
And here at GcmBroadcastReceiver, when gcm push some data, trigger that magic event in order to perform updates at the UI thread with some views like ListViews or TextView
One way is to use use LocalBroacastManager. For how to implement is, there is a great example on how to use LocalBroadcastManager?.
LocalBroadcast Manager is a helper to register for and send broadcasts of Intents to local objects within your process. The data you are broadcasting won't leave your app, so don't need to worry about leaking private data.`
Your activity can register for this local broadcast. From the GCMBroadcastReceiver, you send a local broadcast when you receive something in GcmBroadcastReceiver. Inside your Activity you can listen to the broadcast. This way if the activity is in the forefront/is active, it will receive the broadcast otherwise it won't. So, whenever you receive that local broadcast, you may do the desired action if activity is open. This is like saying to the activity that "Hey Activity, I've received a message. Do whatever you want with it".
If you want to do for the whole app, then you can make all your activities extend an abstract activity. And inside this abstract activity class you can register it for this 'LocalBroadcast'. Other way is to register for LocalBroadcast inside all your activities (but then you'll have to manage how you'll show the message only once).
You can use Handlers in your MainActivity in order to comunicate with UI Thread.
Communicating with the UI Thread
public class MainActivity extends Activity{
public static final int NEW_DATA_AVAILABLE = 0;
public static final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MainActivity.NEW_DATA_AVAILABLE:
String newData = msg.getData().getString(MyClass.DATA);
//Do some stuff with newData
break;
}
}
};
}
and in your non Activity class
public class MyClass implements Runnable{
Thread thread;
public final static String DATA = "new_data";
public MyClass(){
thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while(true){
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
Message msg = mHandler.obtainMessage(MainActivity.NEW_DATA_AVAILABLE);
Bundle bundle = new Bundle();
bundle.putString(DATA, "We have received new data");
msg.setData(bundle);
MainActivity.handler.sendMessage(msg);
}
}
}
say I want to perform an Http request from the server, this process takes time.
now because of this, the http request needs to be run on a different thread (AsyncTask, Runnable, etc.)
but sometimes I just need the response when I ask for it, in order to update the UI
using Thread.sleep in a loop to wait for the response is not good performance wise
example: I want the user's name, I ask the server for it, and I have to wait for it
now the activity calls the UserManager that calls the serverHandler that performs the operation and returns the result back
maybe an event system is in order, but I'm not sure how to do this in my scenerio
and quite frankly I am really confused on this issue
please help someone?
This can most definitely be done w/ AsyncTask... Handle the network request in doInBackground() and once doInBackground() is finished, onPostExecute() is triggered on the UI thread and that's where you can execute any code that will update UI elements.
If you need something a bit more generic and re-usable, you would probably want to implement a callback... I'll refer to the UI thread as the client and the AsyncTask as the server.
Create a new interface and create some method stubs.
public interface MyEventListener {
public void onEventCompleted();
public void onEventFailed();
}
Have your client pass instance of MyEventListener to the server. A typical way of doing this is to have your client implement the interface (MyEventListener) and pass itself to the server.
public class MyActivity implement MyEventListener {
public void startEvent() {
new MyAsyncTask(this).execute();
}
#Override
public void onEventCompleted() {
// TODO
}
#Override
public void onEventFailed() {
// TODO
}
}
On the onPostExecute of the server, check if the callback is null and call the appropriate method.
public class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private MyEventListener callback;
public MyAsyncTask(MyEventListener cb) {
callback = cb;
}
[...]
#Override
protected void onPostExecute(Void aVoid) {
if(callback != null) {
callback.onEventCompleted();
}
}
}
You can read more about callbacks here: http://www.javaworld.com/javaworld/javatips/jw-javatip10.html
I need to run a task inside a RMI service and it needs an event listener implemented for it. Right now when I pass the EventListener over RMI it does execute the call however the callback method of the Listener is not being invoked and it remains in the wait state. How should I get this to work?
public class MyEventListener implements Serializable, ABCEventListener {
private static final long serialVersionUID = -4686421592620210489L;
private boolean registrationCompleted = false;
public boolean getRegistrationCompleted(){
return registrationCompleted;
}
#Override
public void onSomethingDiscovered(Agent agent) {
System.out.println("Added agent "+agent.toString()+" to the set \n");
}
#Override
public void onDiscoveryComplete() {
this.registrationCompleted = true;
System.out.println("Discovery process completed. \n");
}
}
Here is where I pass the eventlistener to the RMI service 'ds'
MyEventListener myEL = new MyEventListener();
ds.discoverAsync(val, myEL);
waitForRegistration();
.
.
private void waitForRegistration() {
try{
while(!dcev.getRegistrationCompleted()){
System.out.println("Please wait...");
Thread.sleep(15000);
}
}catch(InterruptedException e){
logger.error("InterruptedException raised while waiting for registration",e);
e.printStackTrace();
}
}
The problem is that because your event listener is serializable the data fields of your event listener get sent across the wire and a new object created on the server side. The method is called on this copy of your event listener. This makes perfect sense for data objects, but for the likes of event listeners doesn't work as you want your client code to get the call.
I believe you can make this work if your event listener extends RemoteObject. If you do this, instead of your object being copied, it will be exposed as an RMI service when you call the server. The server instead of getting a copy of your object, will get a proxy to your event listener. The call to the event listener will result in an RMI call in the reverse direction to call your event listener.
See Passing Remote Objects in the RMI guide for more details.
public class MyActivity extends AbstractActivity implements ContextChangedEvent.Handler
{
public MyActivity()
{
ClientFactory.INSTANCE.getEventBus().addHandler(ContextChangedEvent.TYPE, this);
}
#override
public void onContextChanged()
{
//do stuff
}
}
//The getEventBus Implementation:
public EventBus getEventBus()
{
if (eventBus == null)
eventBus = new ResettableEventBus(new SimpleEventBus());
return eventBus;
}
When I add a breakpoint in the onContextChange() method, I get the following behavior:
on the first Place, i break only once for each event fired
after a place changed, I break twice
after another place change, 3 times....
Since I'm using a new instance of MyActivity for each place, my guess is that I break in several instances of MyActivity. The ResettableEventBus should unregister all handler on each place change.
I am missing something?
With ResettableEventBus you still have to call removeHandlers (plural) to detach everything. ResettableEventBus only keeps track of your handlers and adds a function to remove all handlers that was attached to this instance.
If you are using ActivityManager and passing in your eventbus, ActivityManager will wrap your EventBus in ResettableEventBus and pass it to you in start.
ActivityManager(myActivityMap, ClientFactory.INSTANCE.getEventBus());
...
public class MyActivity extends AbstractActivity implements ContextChangedEvent.Handler
{
public MyActivity()
{
}
#override
public void onContextChanged()
{
// do Stuff
}
#override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
eventBus.addHandler(ContextChangedEvent.TYPE, this);
}
}
If you use the eventBus passed to you in "start", ActivityManager will automatically clean the handlers you attach to it automatically for you.
Also I would suggest constructing a SimpleEventBus in your factory instead of ResettableEventBus. There is a bug in the current version of ResettableEventBus that causes issue if you nest it (Memory Leak).
http://code.google.com/p/google-web-toolkit/issues/detail?id=5700
This is more of a FYI. Also don't remove any handlers manually from the passed in eventbus. This is caused by the same bug as above.