开发者

Is there any callback mechanism in android when there is data available to read in socket

Well I am familiar with socket programming in c, iOS environment..But now trying to connect my android and my remote server via sockets...As a start up, I wrote a simple server program in C and ran it on my desktop which patiently wait for a connection request, accepts connection, then wait for some request string, and on getting the request string returns some response string, then again wait for next request and go on..Well you get the idea..

So far

  1. I have established a connection with my android and server
  2. sent and received data

And this is my client code..

public class SocketMaster {
    private Socket clientSocket     =   null;
        BufferedReader socketReadStream =   null;
    public boolean connectToHost(String ip, int port){
        try {
            InetAddress serverAddr  =   InetAddress.getByName(ip);
            try {
                clientSocket        =   new Socket(serverAddr, port);
                socketReadStream    =   new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                String line     =   null;
                String stringToSend =   "This is from client ...Are you there???";

                //Write to server..stringToSend is the request string..
                this.writeToServer(stringToSend);

                //Now read the response..
                while((line = socketReadStream.readLine()) != null){
                    Log.d("Message", line);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean writeToServer(String stringToSend){
        DataOutputStream dos        =   null;
        try {
            dos                         =   new DataOutputStream(clientSocket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        try {
            dos.write(stringToSend.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

I create an object of SocketMaster from another activity and calls connectToHost passing ip and port of server..Everything works fine and I am able to connect, send and receive data..

Now my question is regarding these lines

//Now read the response..
while((line = socketReadStream.readLine()) != null){
     Log.d("Message", line);
}

From what I understand, the thread that executes this code

  • blocks until there is data to read
  • if data available, read it, then because of loop again blocks until next chunk of data arrives

Simply I can't run this code on main thread as it will block my UI Activities..I can think of running this in a background thread, which is one option...

But Ideally what I want is...

A callback (I think, listener in android terms, anyone familiar with iOS CFSocket and callback),method , which gets called when there is data available to read, so that I can just read data and then return..

Is there any such mechanism in andro开发者_StackOverflow社区id/ java...If not ( :-( ), can anyone link me to some example where socket handling is done in background...

EDIT: I was not asking about creating a callback mechanism myself..I was just asking is there any listener present which notify you when there is data to read, when the connection got disconnected..Thus I can eliminate the above given while loop...If there isn't any callback, I am ready move this socket to another thread, which loops arounds and reads data (which infact I have already done)...

**

EDIT Bounty time again..

**

Well I am 2 weak old android/java developer with a good 3.5 years of c/c++/objective c development experience behind that... So I have seen low level c native sockets (which blocks(configurable) when use read() and recv()) and apple's CFSocket (which is C socket itself but provide a wrapper to provide callback mechanism).. I am not asking about coding a callback mechanism myself here (which I am whole heartedly ready to do if there is no readymade alternative present, but why reinvent the wheel again?)...I am beginning to understand java as very advanced and high level platform.. I thought there should be some higher level wrapper library lurking around..So I am thinking of increasing the audience to this thread by starting a bounty..


There is no ready-made callback for this in Java. You can easily implement one using the classes in the NIO package. You mostly need Selector and SocketChannel. If you are familiar with select(2), should be easy to follow. If not, try a NIO tutorial.

http://download.oracle.com/javase/1.5.0/docs/api/java/nio/channels/SocketChannel.html http://download.oracle.com/javase/1.5.0/docs/api/java/nio/channels/Selector.html

In any case, you will have to poll the socket to check if there is data, and you can't do this on the main thread. Unless your android app should manage multiple connections on the same thread, it might be a lot easier to just use blocking IO. Another thing to consider: if this has to run continuously/for a long time you need to move it to a service. Even then, the OS can kill it, if it runs out of resources, so be ready to handle reconnects.

HTH


Here is something you can try:

Define a handler in java like this

public interface NwkCallback
{
    void handle(int code, Object obj);
}

Now define a class that handles networking operations:

public class Nwk
{
    static DefaultHttpClient    CLIENT  = null;
    static DefaultHttpClient c()
    {
        if (null == CLIENT)
        {
        // Create a httpclient
        }
        else
            return CLIENT;
    }
}
public static void onReceive(final Object data, final NwkCallback callback)
{
    background(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                // Write to server and wait for a response
                // Once you receive a response
                // return result back using
                // callback.handle(1,whatever_server_returned)
            }
            catch (Exception e)
            {
                Logger.e(e);
            }
        }
    }
});

On your UI thread or elsewhere use the method onReceive as

Nwk.onReceive(string_passed_to_server, new NwkCallback()
{
    @Override
    public void handle(final int code, Object obj)
    {
        if(code==1)
        {
            // Print obj
        }
    }
});


If you're looking for a sample of an Android app that uses a service to manage background long-term connections, check out ConnectBot:

http://code.google.com/p/connectbot/source/browse/

It uses a service to manage terminal connections. It's a very complex set of code however, probably take some digging to figure out the bits you want to make use of.

Most folks do server connections via HTTP, and there's a one-to-one mapping between request contexts and callbacks. So we can get away with an IntentService to handle backgrounding the requests, and pass in a ResultReceiver to get the service to call back to the UI thread when the request is completed/failed:

http://developer.android.com/reference/android/os/ResultReceiver.html

The same general technique should apply for long-running socket connections, though you'll probably have to opt for a different form of service so that you can manage the lifecycle on your own. But if you do, you should be able to take an intent in with a ResultReceiver as part of the requeue, queue it up for processing, and then send() on the ResultReceiver to get the callback out to the UI.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜