Android 如何从其他 类 更新(UI 线程)(真的吗?)

Android how to update (UI thread) from other classes (really?)

你可能知道 Google Cloud Messaging

问题是当服务器触发 gcm 消息时,我的应用程序从 google 播放服务接收到一个包,这发生在 GcmBroadcastReceiver.java。在这里,我可以将此数据发送到其他 类,以便从服务器附加一些信息。好吧。我在尝试更新时卡住了,例如,UI 线程中的某些视图。

我该怎么做?

当我声明视图等时,假设 MainActivity.java 是 UI 线程

我试图在这里创建一个public静态方法,可以通过这种方式被GcmBroadcastReceiver.java直接调用:MainActivity.*updateUI*(args..),但是它抛出这个异常:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

谁能帮我解释一下?我也知道 asyncTask 但我无法想象它是如何工作的。我还找到了一些解释由 UI 线程触发的事件的页面,它本身就像在后台执行某些任务的可运行对象。我在搜索这样的东西:

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

    }

} 

并且在 GcmBroadcastReceiver 处,当 gcm 推送一些数据时,触发该魔术事件以便在 UI 线程执行更新,其中包含一些视图,例如 ListViews 或 [=21] =]

一种方法是使用 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.`

您的 activity 可以注册此本地广播。从 GCMBroadcastReceiver,当你在 GcmBroadcastReceiver 中收到一些东西时,你发送一个本地广播。在您的 Activity 中,您可以收听广播。这样,如果 activity 在 forefront/is 活动中,它将接收广播,否则不会。因此,每当您收到该本地广播时,如果 activity 处于打开状态,您可以执行所需的操作。这就像对 activity 说 "Hey Activity, I've received a message. Do whatever you want with it".

如果你想为整个app做,那么你可以让你所有的activity扩展一个抽象activity。在这个摘要 activity class 中,你可以为这个 'LocalBroadcast' 注册它。另一种方法是在您的所有活动中注册 LocalBroadcast(但是您必须管理如何只显示一次消息)。

您可以在 MainActivity 中使用处理程序以便与 UI 线程通信。

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

并且在你的非 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);
        }

    }

}