Java android客户端使用线程与服务器通信的最佳实践

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18303891/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:18:10  来源:igfitidea点击:

Best practice for android client to communicate with a server using threads

javaandroidclient-server

提问by Bob

I am building an android app that communicates with a server on a regular basis as long as the app is running.

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

I do this by initiating a connection to the server when the app starts, then I have a separate threadfor receiving messages called ReceiverThread, this threadreads the message from the socket, analyzes it, and forwards it to the appropriate part of the application.

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

This threadruns in a loop, reading whatever it has to read and then blocks on the read()command until new data arrives, so it spends most of it's time blocked.

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

I handle sending messages through a different thread, called SenderThread. What I am wondering about is: should I structure the SenderThreadin a similar fashion? Meaning should I maintain some form a queue for this thread, let it send all the messages in the queue and then block until new messages enter the queue, or should I just start a new instance of the thread every time a message needs to be sent, let it send the message and then "die"? I am leaning towards the first approach, but I do not know what is actually better both in term of performance (keeping a blocked thread in memory versus initializing new threads), and in terms of code correctness.

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

Also since all of my activities need to be able to send and receive messages I am holding a reference to both threads in my Applicationclass, is that an acceptable approach or should I implement it differently?

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

One problem I have encountered with this is that sometimes if I close my application and run it again I actually have two instances of ReceiverThread, so I get some messages twice.

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

I am guessing that this is because my application did not actually close and the previous thread was still active (blocked on the read()operation), and when I opened the application again a new thread was initialized, but both were connected to the server so the server sent the message to both. Any tips on how to get around this problem, or on how to completely re-organize it so it will be correct?

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

I tried looking up these questions but found some conflicting examples for my first question, and nothing that is useful enough and applies to my second question...

我尝试查找这些问题,但发现我的第一个问题有一些相互矛盾的例子,但没有什么足够有用并且适用于我的第二个问题......

采纳答案by Darwind

1.Your approach is ok, if you reallyneed to keep an open connection between the server and client at all time at all cost. However I would use an asynchronous connection, like sending an HTTP request to the server and then get a reply whenever the server feels like it.

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

If you need the server to reply to the client at some later time, but you don't know when, you could also look into the Google Cloud Messaging framework, which gives you a transparent and consistent way of sending small messages to your clients from your server.

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

You need to consider some things, when you're developing a mobile application.

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

  1. A smartphone doesn't have endless amount of battery.

  2. A smartphone's Internet connection is somewhat volatile and you will lose Internet connection at different times.

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

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

When you keep a direct connection to server all the time, your app keep sending keep-alive packets, which means you'll suck the phone dry pretty fast. When the Internet connection is as unstable as it gets on mobile broadband, you will lose the connection sometimes and need to recover from this. So if you use TCPbecause you want to make sure your packets are received you get to resend the same packets a lot of times and so get a lot of overhead.

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

Also you might run in to threading problems on the server-side, if you open threads on the server on your own, which it sounds like. Let's say you have 200 clients connecting to the server at the same time. Each client has 1 thread open on the server. If the server needs to serve 200 different threads at the same time, this could be quite a performance consuming task for the server in the end and you will need to do a lot work on your own as well.

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

2.When you exit your application, you'll need to clean-up after you. This should be done in your onPausemethod of the Activitywhich is active.

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

This means, killing off all active threads (or at least interupting them), saving the state of your UI (if you need this) and flushing and closing whatever open connections to the server you have.

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

As far as using Threadsgoes, I would recommend using some of the build-in threading tools like Handlersor implementing the AsyncTask.

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

If you really think Threadis the way to go, I would definitely recommend using a Singleton patternas a "manager" for your threading.

如果你真的认为这Thread是要走的路,我绝对会推荐使用单例模式作为线程的“管理器”。

This manager would control your threads, so you don't end up with more than one Threadtalking to the server at any given time, even though you're in another part of the application.

该管理器将控制您的线程,因此Thread即使您在应用程序的另一部分,您也不会在任何给定时间与服务器进行多个对话。

As far as the Applicationclass implementation goes, take a look at the Application class documentation:

Application类实现而言,请查看Application 类文档

Base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml's tag, which will cause that class to be instantiated for you when the process for your application/package is created.

There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way.

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

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

So keeping away from implementing your own Applicationclass is recommended, however if you let one of your Activitiesinitialize your own Singletonclass for managing the Threadsand connections you might (just might) run into trouble, because the initialization of the singleton might "bind" to the specific Activityand so if the specific Activityis removed from the screen and paused it might be killed and so the singleton might be killed as well. So initializing the singleton inside your Applicationimplementation might deem useful.

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

Sorry for the wall of text, but your question is quite "open-ended", so I've tried to give you a somewhat open-ended question - hope it helps ;-)

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