Android how to update (UI thread) from other class

2019-09-02 17:02发布

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

2条回答
Root(大扎)
2楼-- · 2019-09-02 17:48

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

    }

}
查看更多
Melony?
3楼-- · 2019-09-02 17:50

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

查看更多
登录 后发表回答