【Android】NIO相关

【Android】NIO相关

分类: Android   1178人阅读  评论(0)  收藏  举报
什么是NIO:
NIO的全称是New IO,也就是新的IO,源于JDK1.4

NIO入门:
NIO的核心类是Channel和Buffer,其中:
Channel用于读写数据,Buffer用于缓存数据

1、Channel的类型与创建方法:
[java]  view plain copy print ?
  1. //FileChannel:读写文件的Channel  
  2. FileChannel in = fileInputStream.getChannel();  
  3. FileChannel out = fileOuputStream.getChannel();  
  4.   
  5. //DatagramChannel:用于进行UDP连接的Channel  
  6. DatagramChannel udp = DatagramChannel.open();  
  7.   
  8. //SocketChannel:用于进行TCP连接的Channel(Client端)  
  9. SocketChannel tcpClient = SocketChannel.open();  
  10.   
  11. //ServerSocketChannel:用于进行TCP连接的Channel(Server端)  
  12. ServerSocketChannel tcpServer = ServerSocketChannel.open();  
2、Buffer的类型与常用方法:
一个Buffer主要由position, limit, capacity三个变量来控制读写的过程
其中,position为当前指针所在的位置,limit为实际读取的数据长度,capacity为缓冲区的总长度
Buffer的常见类型有:Byte/Char/Short/Int/Long/Float/DoubleBuffer,还有MappedByteBuffer 
[java]  view plain copy print ?
  1. ByteBuffer buffer = ByteBuffer.allocate(1024);  //创建Buffer  
  2. buffer.flip();              //将position清零,以便进行读取   
  3. buffer.clear();             //将position和limit清零,以便进行写入  
  4. channel.read(buffer);       //从buffer中读取数据,从position的位置读取到limit的位置  
  5. channel.write(buffer);      //向buffer中写入数据,从position的位置写入到capacity的位置  
3、字符集的处理:
[java]  view plain copy print ?
  1. Charset charset = Charset.forName("GBK");   //创建字符集  
  2. charset.encode(String source)               //对字符串进行编码  
  3. String result = charset.decode(buffer);     //对Buffer中的内容进行解码并返回String  

NIO进阶:
NIO的最大优点是非阻塞IO,所谓非阻塞IO,是相对于阻塞IO来说的
对于传统的IO,当Server端调用accept()和read()方法时,线程都会被阻塞
而非阻塞IO的原理就是采用事件驱动机制,由Selector类来负责多个通道上事件的检测,并将事件分发给对应的Channel来处理
其中事件的类型为SelectionKey,其中包含了事件的状态信息,以及该事件对应绑定到的Channel

1、Selector的结构模型:
首先将Channel注册到Selector上(Channel的信息会被封装到SelectionKey类型的对象中)
当指定了这个Channel的请求来到时,该SelectionKey就会变成可用状态
这样Selector在轮询的时候,就可以把这个SelectionKey获取出来,并对其进行操作
这样做的好处是可以将多个Channel注册到同一个Selector上,而不用为每个Channel单独启动一个线程并让其阻塞

2、Selector的使用流程:
[java]  view plain copy print ?
  1. //创建并初始化Channel  
  2. SocketChannel client = SocketChannel.open();                //创建Channel  
  3. client.connect(new InetSocketAddress("localhost", port));   //使Channel连接到服务器  
  4.   
  5. //创建Selector,并将Channel注册到Selector上  
  6. Selector selector = Selector.open();                        //创建Selector  
  7. client.configureBlocking(false);                            //将Channel设置成非阻塞  
  8. SelectionKey key = channel.register(selector, SelectionKey.OP_READ);    //注册Channel  
  9. //register方法的第二个参数表示Channel可以进行的操作,共有READ,WRITE,ACCEPT和CONNECT四种操作  
  10. //在将Channel注册到Selector之前,必须保证是非阻塞的,否则将抛出IllegalBlockingModeException异常  
  11.   
  12. //通过Selector轮询可以进行操作的Channel,并通过SelectionKey对Channel进行操作  
  13. while(true) {  
  14.     int readyCount = selector.select(1000); //在指定的时间内,返回可以进行操作的Channel的数量  
  15.         if(readyCount == 0continue;       //如果没有可以进行操作的Channel,则不执行任何操作  
  16.         Iterator<selectionkey> iter = selector.selectedKeys.iterator();  
  17.         while(iter.hasNext()){  
  18.             SelectionKey key = iter.next();   
  19.             if (key.isReadable()) {  
  20.                 handleRead(selector, key);  
  21.             }  
  22.         }  
  23.         iter.remove();  
  24.     }  
  25. }  
  26.   
  27. /** 处理接收到的消息 */  
  28. private void handleRead(Selector selector, SelectionKey key) throws Exception{  
  29.     int length = 0;  
  30.     String content = "";  
  31.     ByteBuffer readBuffer = ByteBuffer.allocateDirect(10240);  
  32.     SocketChannel channel = (SocketChannel) key.channel();  
  33.   
  34.     while ((length = channel.read(readBuffer)) > 0) {  
  35.         readBuffer.flip();  
  36.         while (readBuffer.hasRemaining()) {  
  37.             int size = readBuffer.remaining();  
  38.             byte [] contentBuffer = new byte[size];  
  39.             readBuffer.get(contentBuffer);  
  40.             content = new String(contentBuffer);  
  41.             Log.i(TAG, "Message Received! Content: " + content);  
  42.         }  
  43.         readBuffer.clear();  
  44.     }  
  45.   
  46.     //如果接收信息结束,则关闭Channel  
  47.     if (length < 0) {  
  48.        Log.i(TAG, "Client disconnected!");  
  49.        channel.close();  
  50.     }  
  51. }  
  52. </selectionkey>  
3、SelectionKey的常用方法:
[java]  view plain copy print ?
  1. selectionKey.channel();         //获取其中封装的Channel对象  
  2. selectionKey.isReadable();      //判断selectionKey的注册类型是否为OP_READ  
  3. selectionKey.isWriteable();     //判断selectionKey的注册类型是否为OP_WRITE  
  4. selectionKey.isAcceptable();    //判断selectionKey的注册类型是否为OP_ACCEPT  
  5. selectionKey.isConnectable();   //判断selectionKey的注册类型是否为OP_CONNECT  

Android中使用NIO的注意事项:
由于Android2.2中对IPv6的协议支持有BUG,因此在2.2中如果使用NIO,应当在类中添加以下静态代码:
[java]  view plain copy print ?
  1. static {  
  2.     //解决Android2.2系统中不能启用IPV6协议的问题  
  3.     java.lang.System.setProperty("java.net.preferIPv4Stack""true");  
  4.     java.lang.System.setProperty("java.net.preferIPv6Addresses""false");  
  5. }  

此外,由于Android4.0规范不允许在主线程中进行网络连接等耗时操作
因此在开发时,所有的NIO操作都应放到子线程中进行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值