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

1

14

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

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

This thread runs 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.

I handle sending messages through a different thread, called SenderThread. What I am wondering about is: should I structure the SenderThread in 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.

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 Application class, is that an acceptable approach or should I implement it differently?

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.

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?

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...

Canara answered 18/8, 2013 at 21:33 Comment(3)
"Closing" the app is not actually killing it. It just keeps running and especially threads are in no way automatically stoppedSchacker
@Schacker yes I am aware of that, this is my problem. The question is: how to stop the thread reliably? OR how to implement the same overall application in a way that avoids this problem?Canara
That is indeed tricky. Thread#interrupt() (+Socket#close()) can be used to stop it but the hard part is to keep track of whether Application is running or just idle in background. Each activity can do that from onStart on onStop for example.Schacker
P
20

1. Your approach is ok, if you really need 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.

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.

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.

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 TCP because 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.

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.

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

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.

As far as using Threads goes, I would recommend using some of the build-in threading tools like Handlers or implementing the AsyncTask.

If you really think Thread is the way to go, I would definitely recommend using a Singleton pattern as a "manager" for your threading.

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

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

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.

So keeping away from implementing your own Application class is recommended, however if you let one of your Activities initialize your own Singleton class for managing the Threads and connections you might (just might) run into trouble, because the initialization of the singleton might "bind" to the specific Activity and so if the specific Activity is 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 Application implementation might deem useful.

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 ;-)

Pancreatotomy answered 18/8, 2013 at 22:40 Comment(2)
Thank you, though I am still not completely sure about what exactly to do, your answer did help. I know that developing for mobile phones has many aspects to it like preserving battery life, however I do need a constant connection due to my use case of the app. The app usage should be generally short, 5 minutes is generally more than enough, however during those 5 minutes many interactions over the internet should occur. I really don't think keeping a connection alive for 5 minutes would drain the battery dry, would it?Canara
@Canara 5 minutes is fine. Regular updates in background are problematic. see developer.android.com/training/efficient-downloads/index.htmlSchacker

© 2022 - 2024 — McMap. All rights reserved.