我目前正在开发一款仅供个人使用的Android应用程序。应用程序通过TCP套接字与服务器通信。如果用户输入,则需要立即发送。此外,在任何给定时间都可能有来自服务器的消息需要在UI上显示。对于所有的网络内容,我都有一个后台主题。
由于我需要在任何用户输入时将消息从UI传递到网络线程,并且在任何给定时间都将消息从网络线程传递到UI,我的问题如下:我如何传递消息?我已经阅读了3小时的Handler类,我无法弄明白。处理程序如何工作?什么是一个整洁和平稳运行的实现?我更多地寻求实现这一目标的战略,而不一定是实施细节。
提前非常感谢你!
答案 0 :(得分:1)
http://developer.android.com/reference/android/os/AsyncTask.html使用此我处理程序也遇到了很多问题,但异步任务处理所有烦人的工作。确保使用onPrexecute()和onPostExecute()来更新UI。希望这可以帮助。
答案 1 :(得分:1)
在这种情况下,您可以使用AsyncTask
。
您可以在UI线程上调用它,并在onPostExecute中执行您要对消息执行的操作。
这比在那里进行所有脏网络工作要简洁得多。
答案 2 :(得分:1)
首先,我会说我自己也在学习,但我已经设法在原型中使用这个确切的设置。如果有人看到应该更改的内容以便在Android中更好地工作,请务必告诉我。
其次,我正在使用空消息,以便我们拥有实际可行的代码。我认为创建消息对象非常简单。
就我所见,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()
有几种不同的方法可以解决这个问题。您可以在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>
您还可以将View
或runOnUIThread(Runnable)
传递给网络线程,并从该调用{{1}}传入,但这需要您传入Runnable。因此,要在UI上工作的代码正在网络类中编写或引用。
您也可以使用服务。当活动和网络具有相同的生命周期时,上述方法有效。如果我们只在活动处于活动状态时需要网络连接。
如果您需要超出活动生命周期的网络连接,例如在音乐流媒体应用中,那么使用服务将是更好的选择。这似乎不是你特别想要的问题。