2

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

由于我需要在任何用户输入时将消息从 UI 传递到网络线程,并且在任何给定时间将消息从网络线程传递到 UI,我的问题如下:如何传递消息?我已经阅读了 3 个小时的 Handler 类,但我什么也想不通。处理程序如何工作?什么是一个整洁而流畅的运行实现?我更多地寻找实现这一目标的策略,而不一定是实现细节。

非常感谢您!

4

3 回答 3

1

首先,我会说我自己正在学习这个,但我已经设法让这个精确的设置在原型中工作。如果有人看到应该更改以在 Android 中更好地工作的东西,请务必告诉我。

其次,我使用空消息,以便我们拥有可以实际工作的代码。我认为创建消息对象是直截了当的。

第 1 部分 - 网络线程的 UI

据我所知,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()调用之间创建 Handler 对象。run()我不知道幕后的魔力,还没有机会在兔子洞里走得那么远。

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

所以,重命名LooperThreadNetworkThread,或者任何你想要的名字,并将你的连接代码放在run()方法中,但在Looper.prepare() / Looper.loop()块之外(我不知道魔法是如何工作的,所以我只是假设这更好做的比把它放在里面)。

// process incoming messages here

往往看起来像这样:

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

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

因此,在您的活动代码中的某处,您创建NetworkThread对象、运行它,然后从中获取处理程序。

NetworkThread network = new NetworkThread();
new Thread(network).run();
//Handler networkHandler = network.handler;
Handler networkHandler = network.getHandler();

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

networkHandler.sendEmptyMessage(1);

第 2 部分 - 到 UI 的网络线程

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

在我的代码中,我在onCreate()方法中创建了一个处理程序,然后将它传递给我的NetworkThread对象。可能有更好的地方来创建这个处理程序,我不知道如果您的应用程序被暂停然后稍后再次启动会发生什么onResume()onRestart()

public NetworkThread(Handler mainHandler)
{
    this.mainHandler = mainHandler;
}

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

this.mainHandler.sendEmptyMessage(1);

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

您也可以将Activityor传递View给网络线程并从该 callrunOnUIThread(Runnable)传递,但这需要您传递 Runnable。因此,在网络类中编写或引用了用于 UI 的代码。


更新

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

如果您需要 Activity 生命周期之外的网络连接,例如在音乐流媒体应用中,那么使用 Service 将是更好的选择。看起来这并不是您要寻找的问题。

于 2012-11-09T04:17:15.290 回答
1

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

于 2012-04-16T19:34:52.017 回答
1

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

于 2012-04-16T19:36:14.023 回答