I'm quite new to java and Android programming and have come across the following problem...
I've written a generic thread that sends a message over tcp to a server, waits for a response, then returns the response through a handler to the activity that started the thread.
When the activity needs to send a message to the server, it creates the thread, passing the handler in the constructor.
The handler in the activity processes the response from the server.
The issues is that there are multiple activities that will invoke this thread and each activity will handle responses differently.
For example:
In MainActivity I have a MainActivity.TcpClientHandler
In LightSettingsActivity I have a LightSettingActivitiy.TcpClientHandler
In MainActivity I invoke the thread when I need to send a message and wait a response:
tcpClientThread = new TcpClientThread (serverAddress,serverPort,message,tcpClientHandler);
In LightSettingsActivity, the same:
tcpClientThread = new TcpClientThread (serverAddress,serverPort,message,tcpClientHandler);
In my Thread class, I had to treat these as two different constructors
public TcpClientThread(String addr, int port,String outputMessage, MainActivity.TcpClientHandler handler)...
and
public TcpClientThread(String addr, int port,String outputMessage, LightSettingsActivity.TcpClientHandler handler)...
This doesn't seem very efficient and make my code kind of complex because even when sending the response back to the hander, I need to pay attention to the class that originated the thread,
Like I have to do things like this:
if(threadType == THREAD_MAIN)
handler.sendMessage(Message.obtain(handlerMainActivity, CommonLabels.UPDATE_MSG, inputMessage));
else if(threadType == THREAD_LIGHT_SETTINGS)
handlerLightSettings.sendMessage(Message.obtain(handlerLightSettings, CommonLabels.UPDATE_MSG, inputMessage));
Is there a more efficient way to do this (I tried to use callback instead of handler, but I had a whole set of other problems)?
TcpClientHandler needs to be an interface. LightSettingsActivity and MainActivity need to either implement it or contain an implementation that is specific to them.
When you create a TcpClientThread it looks like this for all handlers
public TcpClientThread(String addr, int port,String outputMessage,TcpClientHandler handler)...
As for the last problem since both activities have their own implementation of TcpClientHandler you do not need to differentiate between them because they are unrelated. In reality using an interface in this fashion is a callback but that is generally how you solve this problem. Because you want to callback to the originator of the request not every class that happens to use TcpClientThread
Related
I am using the StreamObserver class found in the grpc-java project to set up some bidirectional streaming.
When I run my program, I make an undetermined number of requests to the server, and I only want to call onCompleted() on the requestObserver once I have finished making all of the requests.
Currently, to solve this, I am using a variable "inFlight" to keep track of the requests that have been issued, and when a response comes back, I decrement "inFlight". So, something like this.
// issuing requests
while (haveRequests) {
MessageRequest request = mkRequest();
this.requestObserver.onNext(request);
this.inFlight++;
}
// response observer
StreamObserver<Message> responseObserver = new StreamObserver<Message> {
#Override
public void onNext(Message response) {
if (--this.onFlight == 0) {
this.requestObserver.onCompleted();
}
// work on message
}
// other methods
}
A bit pseudo-codey, but this logic works. However, I would like to get rid of the "inFlight" variable if possible. Is there anything within the StreamObserver class that allows this sort of functionality, without the need of an additional variable to track state? Something that would tell the number of requests issued and when they completed.
I've tried inspecting the object within the intellij IDE debugger, but nothing is popping out to me.
To answer your direct question, you can simply call onComplete from the while loop. All the messages passed to onNext. Under the hood, gRPC will send what is called a "half close", indicating that it won't send any more messages, but it is willing to receive them. Specifically:
// issuing requests
while (haveRequests) {
MessageRequest request = mkRequest();
this.requestObserver.onNext(request);
this.inFlight++;
}
requestObserver.onCompleted();
This ensures that all responses are sent, and in the order that you sent them. On the server side, when it sees the corresponding onCompleted callback, it can half-close its side of the connection by calling onComplete on its observer. (There are two observers on the server side one for receiving info from the client, one for sending info).
Back on the client side, you just need to wait for the server to half close to know that all messages were received and processed. Note that if there were any errors, you would get an onError callback instead.
If you don't know how many requests you are going to make on the client side, you might consider using an AtomicInteger, and call decrementAndGet when you get back a response. If the return value is 0, you'll know all the requests have completed.
I am developing an app which displays data from a server. The server is not mine and it is not very stable. Making too many connections crashes the server.
I have one socket to the server in my main activity, but at times I want to open sub activities which read the data and display it. My problem is that I am unable to achieve this with the same socket and have to open a new socket for every activity.
Every activity has a thread which does the reading from the socket and updates the UI elements on that activity as needed.
To use the same socket in multiple activities, I tried to close the inputReader of an activity before starting the new activity, but that simply make the application hang. If I leave it open, then the new thread in the new activity never receives any data. Killing the thread before starting the new activity is not possible because the thread is generally blocked by the read() function.
Is there anyway that I can have a centralized thread which does the reading and then sends the data to all the other threads in other activities so that I don't have to open new sockets in every activity?
I feel that this is a very basic thing that I am asking, but yet I am unable to find a solution.
A pretty straightforward and simple approach is the following:
You create a new Service which runs in the background and communicates with the server through your socket
The Service receives data from the socket and forwards/broadcasts it to all of your Activities which are interested in receiving it (for example to update the UI) by using the LocalBroadcastManager
All of your Activities implement a BroadcastReceiver and receive the data from your Service inside the onReceive() method
To accomplish that, you should read the introduction to Services and BroadcastReceivers to get an idea of how they work. Also to get a basic overview first, you should read about the available App Components.
EDIT, to answer the question in the comment:
You can always stop the Service by calling stopService() but you can also do it differently if you don't want/need all the functionality of a Service. Instead of a Service you could also create a simple Thread or a HandlerThread which communinicates with the server. From inside of your Thread, you can then forward/broadcast the data to your Activities by using the technique mentioned above (LocalBroadcastManager).
Just to give you an example of the basic structure (code untested though):
class SocketThread implements Runnable
{
static final String SOCKET_DATA_RECEIVED = "com.your.package.SOCKET_DATA_RECEIVED";
static final String SOCKET_DATA_IDENTIFIER = "com.your.package.SOCKET_DATA";
private Context context;
SocketThread(Context c) {
context = c.getApplicationContext();
}
#Override
public void run() { // code running in your thread
// fetch data from socket ...
Intent intent = new Intent();
intent.putExtra(SOCKET_DATA_IDENTIFIER, data); // store data in your intent
// send data to registered receivers
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
// your code ...
}
}
Then you have your Activities, for example MyActivity1, MyActivity2, ... MyActivityN. They all register their embedded SocketDataReceiver to receive the broadcast intent SOCKET_DATA_RECEIVED, which is sent by your thread.
Inside your onReceive() methods you can then extract the data from your intent object by using the identifier SOCKET_DATA_IDENTIFIER.
public class MyActivity1 extends Activity
{
private SocketDataReceiver socketDataReceiver;
#Override
protected void onResume() {
super.onResume();
socketDataReceiver = new SocketDataReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(
socketDataReceiver, new IntentFilter(SocketThread.SOCKET_DATA_RECEIVED));
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(socketDataReceiver);
}
private class SocketDataReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
// intent contains your socket data,
// get data from intent using SocketThread.SOCKET_DATA_IDENTIFIER
}
}
}
Basically you answered your question yourself:
I can have a centralized thread which does the reading and then sends the data to all the other threads in other activities.
Meaning: of course, such a thing is possible. But you have to sit down, design and implement it. You would start by defining a reasonable interface that allows your other threads to communicate with that central service, something like:
enum RequestType { DO_THIS, DO_THAT };
interface ServerConnectionService<T> {
List<T> performRequest(RequestType request);
}
Meaning: instead of having your different threads do "low level" talking on that socket, you create an abstraction that allows you to say: "when I need this kind of information, then I use my service; and it returns some specific answer to me). Of course, this is a very generic answer, but well, your question isn't exactly specific either.
The next step would then be to have some central (maybe singleton) implementation of that interface; which runs on its own thread, and can be used by other threads in a synchronized, well-defined way.
Final word of warning: if you don't own that server, and it has low quality and is causing trouble for you - that is not a good setup. Because no matter what you do in your code, if the server doesn't do a good job, users will perceive your app to be the problem. Users don't care if an operation fails because some remote server crashes. So the other aspect in your question is: right now, you are in a bad spot. You should spent some serious time to find ways out of there. Otherwise you will be wasting a lot of time to build workarounds for that server you are dealing with.
I am trying to integrate apacahe Mina in android.
Can we persist objects using AsyncTask & pass to UI or another class for further use?
for example
public class NetworkConnect extends AsyncTask<String, Void, String>{
#Override
protected String doInBackground(String... param) {
Protocol p = new Protocol(); //here I m making connection with echo server
//Now I want that session in UI to send messages to echo Server
}
}
I want to use this 'p' instance in other class(Like UI) and using this 'p' instance call to attributes of Protocol class.
How to do that? or Is there any alternative solution?
Basically 'Protocol' class should run parallel to UI thread and based on events both should be able to communicate with each other.
Suppose there is echo server...then when someone enter input to 'Input' edittext and hit 'send' button, echoServer will give me back this 'input' again.
Now my problem is that using AsyncTask I am able to connect server, But I am unable to using same session in UI. So I can't send data to server.
Thank you
You just need to store a reference to that object in a field (rather than a local variable like you showed), and provide methods to use it as needed. If it needs to always run on a background thread, then those methods can start an AsyncTask.
I'm struggling to wrap my head around what needs to happen here. I'm currently working on an app that runs a service. The service when started opens a webserver that runs in a background thread.
At any point while this service is running the user can send commands to the device from a browser. The current sequence of events is as follows.
User sends request to server
Server sends a message to the service via the msg handler construct, it sends data such as the url parameters
The service does what it wants with the data, and wants to send some feedback message to the user in the browser
?????
The server's response to the request contains a feed back message from the service.
The way my functions are set up I need to pause my serve() function while waiting for a response from the service and then once the message is received resume and send an http response.
WebServer.java
public Response serve( String uri, String method, Properties header, Properties parms, Properties files )
{
Bundle b = Utilities.convertToBundle(parms);
Message msg = new Message();
msg.setData(b);
handler.sendMessage(msg);
//sending a message to the handler in the service
return new NanoHTTPD.Response();
}
CommandService.java
public class CommandService extends Service {
private WebServer webserver;
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
execute_command(msg.getData());//some type of message should be sent back after this executes
};
Any suggestions? Is this structure the best way to go about it, or can you think of a better design that would lead to a cleaner implementation?
I think the lack of answers is because you haven't been very specific in what your question is. In my experience it's easier to get answers to simple or direct questions that general architecture advice on StackOverflow.
I'm no expert on Android but I'll give it a shot. My question is why you have a Webservice running in the background of a Service, why not just have one class, make your Service the Webservice?
Regarding threading and communication and sleeping, the main thing to remember is that a webserver needs to always be available to serve new requests, whilst serving current requests. Other than that, it's normal that a client will wait for a thread to complete its task (i.e. the thread "blocks"). So most webservers spawn new a thread to handle each request that comes in. If you have a background thread but you block the initial thread while you wait for the background thread to complete its task, then you're no better off than just completing everything on the one thread. Actually, the latter would be preferable for the sake of simplicity.
If Android is actually spawning new threads for you when requests come in, then there's no need for a background thread. Just do everything synchronously on one thread and rejoice in the simplicity!
Just started playing around with netty in implementing my own server. Took me a while to get the hang of it but now I was able to accept clients by writing my own MessageHandler and inside messageReceived I was able to read from the buffer and did some business logic related to the data received.
However the question now is, how do I write data into connected clients? I saw the sample code where you can write to the channel in the event of a new message like this:
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
Channel ch = e.getChannel();
ch.write(e.getMessage());
}
but what if you don't want to write the data back at that point? What if the client stays connected in the socket and waits until some event occurs in the server? In that case how will my server find the right socket to write to? Am I suppose to keep a reference to the channel object? Is this the convention?
I looked further into the code and saw a method called writeRequested. Is that related? Who calls that? And is it needed?
As long as you have the reference to the Channel (or ChannelHandlerContext), you can call Channel.write() (or Channels.write()) from anywhere, any thread.
writeRequested() is called when you trigger the writeRequested event by calling Channel.write() or calling ChannelHandlerContext.sendDownstream(MessageEvent).