0

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

Marcus
  • 6,697
  • 11
  • 46
  • 89
k1r0s
  • 359
  • 3
  • 14
  • dont call a static method, create a broadcast receiver in your `MainActivity` then in your `GcmBroadcastReceiver` send a broadcast to your activity telling it what to do (refresh/update) – tyczj Feb 23 '15 at 19:44

2 Answers2

3

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).

Community
  • 1
  • 1
Shobhit Puri
  • 25,769
  • 11
  • 95
  • 124
  • Okay, but if every activity has his own "localBoardcast".. which one will trigger when gcm comes from the server? – k1r0s Feb 23 '15 at 19:48
  • I pretend to build an app that basically share a list of items between devices. Like Google Keep. – k1r0s Feb 23 '15 at 19:49
  • It will be received by ALL those activities which register for the specific Local Broadcast. If you want it on just one activity you can register for the broadcast in that one activity. If you register multiple activities, you can choose to take the action based on the activity you are in. If you just want it to trigger once, you can declare it in the `abstract` activity and make all other activities extend that. It depends on how you've designed your current application. – Shobhit Puri Feb 23 '15 at 19:54
  • @IvanReed Glad the answer helped you. :) – Shobhit Puri Feb 23 '15 at 20:59
2

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);
        }

    }

}