当有数据可用于在socket中读取时,android中是否有任何回调机制

时间:2011-07-30 07:31:19

标签: android sockets asynchronous callback listener

我熟悉c,iOS环境下的套接字编程。但现在尝试通过套接字连接我的android和我的远程服务器......作为一个启动,我在C中编写了一个简单的服务器程序并运行它我的桌面耐心地等待连接请求,接受连接,然后等待一些请求字符串,并在获取请求字符串时返回一些响应字符串,然后再次等待下一个请求然后继续..你明白了... < / p>

到目前为止

  1. 我与我的Android和服务器建立了连接
  2. 发送和接收数据
  3. 这是我的客户代码..

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

    我从另一个活动创建一个SocketMaster对象,并调用connectToHost传递ip和服务器端口。一切正常,我能够连接,发送和接收数据..

    现在我的问题是关于这些行

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

    据我所知,执行此代码的线程

    • 阻止,直到有数据要读
    • 如果数据可用,请阅读,然后因为循环再次阻塞直到 下一个数据块到达

    我只能在主线程上运行此代码,因为它会阻止我的UI活动。我可以考虑在后台线程中运行它,这是一个选项......

    但理想情况下我想要的是......

    回调(我认为,Android方面的监听器,熟悉iOS CFSocketcallback的任何人)方法,当有数据可供读取时调用,以便我可以只读取数据然后返回..

    android / java中是否有这样的机制...如果不是(:-(),有人可以将我链接到一些在后台完成套接字处理的例子......

    修改 我自己并没有要求创建一个回调机制。我只是问是否有任何监听器存在,当有数据要读,连接断开时通知你。因此我可以消除上面给出的循环...如果没有任何回调,我准备将此套接字移动到另一个线程,该线程循环并读取数据(事实上我已经完成了)...

    **

    再次编辑赏金时间..

    **

    嗯,我是2弱的老android / java开发人员,具有良好的3。5年c / c ++ / objective c开发经验...所以我看到了低级c本机套接字(当使用read时阻塞(可配置) ()和recv())和apple的CFSocket(它是C socket本身,但提供了一个提供回调机制的包装器).. 我不是在问自己编写一个回调机制(我是整个如果没有现成的替代礼物,但为什么要重新发明轮子呢?)...我开始理解java作为非常先进和高水平的平台..我认为应该有一些更高级别的包装库潜伏在周围..所以我想通过开始赏金来增加观众到这个线程..

3 个答案:

答案 0 :(得分:8)

Java中没有现成的回调函数。您可以使用NIO包中的类轻松实现一个。你最需要Selector和SocketChannel。如果您熟悉select(2),应该很容易理解。如果没有,请尝试NIO教程。

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

在任何情况下,您都必须轮询套接字以检查是否有数据,并且您不能在主线程上执行此操作。除非您的Android应用程序应该在同一个线程上管理多个连接,否则使用阻塞IO可能要容易得多。另一件需要考虑的事情是:如果必须连续运行/很长一段时间,您需要将其移至服务中。即便如此,如果资源耗尽,操作系统也可以杀死它,因此请准备好处理重新连接。

HTH

答案 1 :(得分:1)

您可以尝试以下方法:

在java中定义一个像这样的处理程序

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

现在定义一个处理网络操作的类:

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

在您的UI线程或其他地方使用onReceive方法

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

答案 2 :(得分:1)

如果您正在寻找使用服务管理后台长期连接的Android应用示例,请查看ConnectBot:

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

它使用服务来管理终端连接。然而,这是一组非常复杂的代码,可能需要花一些时间来计算出你想要使用的位。

大多数人通过HTTP进行服务器连接,并且在请求上下文和回调之间存在一对一的映射。因此,我们可以使用IntentService来处理请求的后台处理,并在请求完成/失败时传入ResultReceiver以使服务回调到UI线程:

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

同样的一般技术应该适用于长时间运行的套接字连接,尽管您可能必须选择不同形式的服务,以便您可以自己管理生命周期。但是如果你这样做,你应该能够将一个ResultReceiver的意图作为重新排队的一部分,将其排队等待处理,然后在ResultReceiver上发送()以获得回调给UI的回调。