【问题标题】:Best practice for android client to communicate with a server using threadsandroid客户端使用线程与服务器通信的最佳实践
【发布时间】:2013-08-20 15:57:32
【问题描述】:

我正在构建一个 Android 应用程序,只要该应用程序正在运行,它就会定期与服务器通信。

我通过在应用程序启动时启动与服务器的连接来做到这一点,然后我有一个单独的thread 用于接收名为ReceiverThread 的消息,这个thread 从socket 读取消息,分析它,并将其转发到应用程序的适当部分。

这个thread 在一个循环中运行,读取它必须读取的任何内容,然后阻塞read() 命令直到新数据到达,因此它大部分时间都被阻塞了。

我通过另一个线程处理发送消息,称为SenderThread。我想知道的是:我应该以类似的方式构建SenderThread 吗?意思是我应该为这个线程维护某种形式的队列,让它发送队列中的所有消息然后阻塞直到新消息进入队列,或者我应该在每次需要发送消息时启动一个新的线程实例,让它发送消息然后“死”?我倾向于第一种方法,但我不知道在性能(将阻塞线程保留在内存中与初始化新线程)和代码正确性方面实际上哪个更好。

此外,由于我的所有活动都需要能够发送和接收消息,因此我在 Application 类中持有对两个线程的引用,这是一种可接受的方法还是我应该以不同的方式实现它?

我遇到的一个问题是,有时如果我关闭我的应用程序并再次运行它,我实际上有两个 ReceiverThread 实例,所以我收到了两次消息。

我猜这是因为我的应用程序实际上并没有关闭并且前一个线程仍然处于活动状态(在read() 操作中被阻塞),当我再次打开应用程序时,一个新线程被初始化,但两者都已连接到服务器,因此服务器将消息发送给两者。有关如何解决此问题或如何完全重新组织它以使其正确的任何提示?

我尝试查找这些问题,但在我的第一个问题中发现了一些相互矛盾的示例,没有任何有用且适用于我的第二个问题的示例...

【问题讨论】:

  • “关闭”应用程序实际上并没有杀死它。它只是保持运行,尤其是线程不会自动停止
  • @zapl 是的,我知道,这是我的问题。问题是:如何可靠地停止线程?或者如何以避免此问题的方式实现相同的整体应用程序?
  • 这确实很棘手。 Thread#interrupt() (+Socket#close()) 可用于停止它,但困难的部分是跟踪应用程序是否正在运行或只是在后台空闲。例如,每个活动都可以从 onStart 到 onStop 执行此操作。

标签: java android client-server


【解决方案1】:

1. 如果您真的需要不惜一切代价始终保持服务器和客户端之间的开放连接,那么您的方法是可以的。但是我会使用异步连接,例如向服务器发送 HTTP 请求,然后在服务器愿意时得到回复。

如果您需要服务器稍后回复客户端,但您不知道何时回复,您也可以查看Google Cloud Messaging framework,它为您提供了一种透明且一致的方式将小消息发送到您的来自您服务器的客户端。

在开发移动应用程序时,您需要考虑一些事情。

  1. 智能手机没有无穷无尽的电池。

  2. 智能手机的互联网连接有些不稳定,您会在不同的时间失去互联网连接。

当您始终保持与服务器的直接连接时,您的应用会不断发送保持活动数据包,这意味着您会很快将手机吸干。 当互联网连接与移动宽带一样不稳定时,您有时会失去连接,需要从中恢复。因此,如果您使用TCP 是因为您想确保收到您的数据包,您会多次重新发送相同的数据包,因此会产生很多开销。

如果您自己在服务器上打开线程,您可能会在服务器端遇到线程问题,这听起来很像。假设您有 200 个客户端同时连接到服务器。每个客户端在服务器上打开 1 个线程。如果服务器需要同时为 200 个不同的线程提供服务,那么这最终对服务器来说可能是一项相当消耗性能的任务,而且您还需要自己做很多工作。

2. 退出应用程序后,您需要进行清理。这应该在您的 Activity 的 onPause 方法中完成,该方法处于活动状态。

这意味着,关闭所有活动线程(或至少中断它们),保存 UI 的状态(如果需要)并刷新和关闭与您拥有的服务器的任何打开连接。

就使用Threads 而言,我建议使用一些内置线程工具,例如Handlers 或实现AsyncTask。

如果您真的认为 Thread 是可行的方法,我绝对建议您使用 Singleton pattern 作为线程的“管理器”。

此管理器将控制您的线程,因此即使您在应用程序的另一部分中,您在任何给定时间都不会与服务器交谈超过一个 Thread。

就Application类的实现而言,看看Application class documentation:

那些需要维护全局应用程序状态的基类。您可以通过在 AndroidManifest.xml 的标签中指定其名称来提供自己的实现,这将导致在创建应用程序/包的进程时为您实例化该类。

通常不需要子类化应用程序。在大多数情况下,静态单例可以以更加模块化的方式提供相同的功能。

因此,建议不要实现您自己的 Application 类,但是如果您让您的 Activities 之一初始化您自己的 Singleton 类来管理您可能(只是可能)遇到的 Threads 和连接麻烦,因为单例的初始化可能会“绑定”到特定的Activity,因此如果从屏幕上删除特定的Activity 并暂停它可能会被杀死,因此单例也可能会被杀死。因此,在您的 Application 实现中初始化单例可能会很有用。

对不起,文字墙,但你的问题是相当“开放式”的,所以我试图给你一个有点开放式的问题 - 希望它有所帮助;-)

【讨论】:

  • 谢谢,虽然我仍然不完全确定到底该怎么做,但您的回答确实有帮助。我知道为手机开发有很多方面,比如保持电池寿命,但是由于我的应用程序用例,我确实需要持续连接。应用程序的使用通常应该很短,通常 5 分钟就足够了,但是在这 5 分钟内应该会发生许多互联网上的交互。我真的不认为保持连接 5 分钟会耗尽电池电量,不是吗?
  • @Bob 5 分钟就可以了。后台定期更新是有问题的。见developer.android.com/training/efficient-downloads/index.html
猜你喜欢
  • 1970-01-01
  • 2012-05-24
  • 2020-11-11
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多