在UI线程和后台网络线程之间交换消息

时间:2012-04-16 19:31:57

标签: java android

我目前正在开发一款仅供个人使用的Android应用程序。应用程序通过TCP套接字与服务器通信。如果用户输入,则需要立即发送。此外,在任何给定时间都可能有来自服务器的消息需要在UI上显示。对于所有的网络内容,我都有一个后台主题。

由于我需要在任何用户输入时将消息从UI传递到网络线程,并且在任何给定时间都将消息从网络线程传递到UI,我的问题如下:我如何传递消息?我已经阅读了3小时的Handler类,我无法弄明白。处理程序如何工作?什么是一个整洁和平稳运行的实现?我更多地寻求实现这一目标的战略,而不一定是实施细节。

提前非常感谢你!

3 个答案:

答案 0 :(得分:1)

http://developer.android.com/reference/android/os/AsyncTask.html使用此我处理程序也遇到了很多问题,但异步任务处理所有烦人的工作。确保使用onPrexecute()和onPostExecute()来更新UI。希望这可以帮助。

答案 1 :(得分:1)

在这种情况下,您可以使用AsyncTask。 您可以在UI线程上调用它,并在onPostExecute中执行您要对消息执行的操作。 这比在那里进行所有脏网络工作要简洁得多。

答案 2 :(得分:1)

首先,我会说我自己也在学习,但我已经设法在原型中使用这个确切的设置。如果有人看到应该更改的内容以便在Android中更好地工作,请务必告诉我。

其次,我正在使用空消息,以便我们拥有实际可行的代码。我认为创建消息对象非常简单。

第1部分 - 网络线程的用户界面

就我所见,Handler是您需要的答案,但并不是全局。 Deucalion对Looper的评论是你需要关注的地方。

http://developer.android.com/reference/android/os/Looper.html

class LooperThread extends Thread {
  public Handler mHandler;

  public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
          }
      };

      Looper.loop();
  }
}

首先,此设置具有反直觉性,您需要在Looper.prepare()方法内的Looper.loop()run()调用之间创建Handler对象。我不知道幕后的魔力,还没有机会在兔子洞里走得那么远。

重要提示: 该示例显示正在创建的匿名Handler()。我强烈建议在你自己的类中继承Handler,然后使用它的实例。这只是一个可重用性的问题,很多网络代码最终都是一样的。

因此,将LooperThread重命名为NetworkThread,或者将其重命名为run(),并将您的连接代码放在Looper.prepare() / Looper.loop()方法中,但在// process incoming messages here 之外阻止(再次我不知道魔法是如何工作的,所以我只是假设这样做比把它放在里面更好)。

switch(msg.what)
{
    case 1:
        break;
    default:
        break
}

看起来像这样:

public Handler mHandler;

LooperThread示例有NetworkThread但我更喜欢将处理程序设为私有并创建一个返回它的方法。我这样做只是为了防止在建立网络连接之前可以访问处理程序。没有联系,与消息无关。

因此,在您的活动代码中的某个位置创建NetworkThread network = new NetworkThread(); new Thread(network).run(); //Handler networkHandler = network.handler; Handler networkHandler = network.getHandler(); 对象,运行它,然后从中获取Handler。

networkHandler.sendEmptyMessage(1);

然后,您只需根据需要向该处理程序发送消息。

onCreate()

第2部分 - 网络线程到UI

有几种不同的方法可以解决这个问题。您可以在Activity类中创建一个处理程序。所有活动都已经设置了Looper,因此调用Looper.prepare和Looper.loop似乎会导致问题。

在我的代码中,我在NetworkThread方法中创建了一个处理程序,然后将其传递给我的onResume()对象。可能有更好的地方来创建此处理程序,我不知道如果您的应用程序被暂停,然后稍后使用onRestart()public NetworkThread(Handler mainHandler) { this.mainHandler = mainHandler; }

再次启动会发生什么
this.mainHandler.sendEmptyMessage(1);

然后我需要向UI发送消息的任何其他地方:

Activity

我更喜欢这种方法,因为执行实际工作的Handler代码要么存在于实际响应消息的类中(使用匿名处理程序对象),要么存在于可能位于同一包中的Handler子类中。 p>

您还可以将ViewrunOnUIThread(Runnable)传递给网络线程,并从该调用{{1}}传入,但这需要您传入Runnable。因此,要在UI上工作的代码正在网络类中编写或引用。


更新

您也可以使用服务。当活动和网络具有相同的生命周期时,上述方法有效。如果我们只在活动处于活动状态时需要网络连接。

如果您需要超出活动生命周期的网络连接,例如在音乐流媒体应用中,那么使用服务将是更好的选择。这似乎不是你特别想要的问题。