Android开发进阶之NIO非阻塞包(七)

今天我们继续就Android DDMS源码一起分析NIO非阻塞通讯方式,Android123也会给大家分享下手机和PC互通中的一些技术。在NIO中有关SocketChannel和ByteBuffer的使用细节,可以在今天文章中

static void read(SocketChannel chan, byte data, int length, int timeout)
throws TimeoutException, IOException {
ByteBuffer buf = ByteBuffer.wrap(data, 0, length != -1 ? length : data.length); //从字节数组中实例化ByteBuffer
int numWaits = 0;

    while (buf.position() != buf.limit()) {  //循环接收数据
        int count;

        count = chan.read(buf);
        if (count < 0) {
                throw new IOException("EOF"); //读到末尾
        } else if (count == 0) {
            if (timeout != 0 && numWaits * WAIT_TIME > timeout) {
                throw new TimeoutException();
            }
             try {
                Thread.sleep(WAIT_TIME);
            } catch (InterruptedException ie) {
            }
            numWaits++;
        } else {
            numWaits = 0;
        }
    }
}

有关SocketChannel的写操作,就是发送数据代码如下:

static void write(SocketChannel chan, byte data, int length, int timeout)
throws TimeoutException, IOException {
ByteBuffer buf = ByteBuffer.wrap(data, 0, length != -1 ? length : data.length);
int numWaits = 0;

    while (buf.position() != buf.limit()) {
        int count;

        count = chan.write(buf); //发送数据从ByteBuffer中
        if (count < 0) {
                   throw new IOException("channel EOF");
        } else if (count == 0) {
                         if (timeout != 0 && numWaits * WAIT_TIME > timeout) {
                        throw new TimeoutException();
            }
             try {
                Thread.sleep(WAIT_TIME);
            } catch (InterruptedException ie) { 
            }
            numWaits++;
        } else {
            numWaits = 0;
        }
    }
}

有关ADB如何选择一个具体的设备,可以使用 setDevice 方法,这样当电脑中有模拟器或链接了多个手机,可以通过设备序列号,选择需要通讯的设备。

static void setDevice(SocketChannel adbChan, IDevice device)
throws TimeoutException, AdbCommandRejectedException, IOException {
// if the device is not -1, then we first tell adb we’re looking to talk
// to a specific device
if (device != null) {
String msg = “host:transport:” + device.getSerialNumber(); // 最后的获取序列号,android123提示大家在adb命令中是adb get-serialno

        byte[] device_query = formAdbRequest(msg); 

        write(adbChan, device_query);

        AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
        if (resp.okay == false) {
            throw new AdbCommandRejectedException(resp.message,
                    true/*errorDuringDeviceSelection*/);
        }
    }
}

通过PC控制手机重启的代码,当然这里需要Root权限才能执行

public static void reboot(String into, InetSocketAddress adbSockAddr,
Device device) throws TimeoutException, AdbCommandRejectedException, IOException {
byte request;
if (into == null) {
request = formAdbRequest(“reboot:”); //NON-NLS-1
} else {
request = formAdbRequest(“reboot:” + into); //NON-NLS-1
}

    SocketChannel adbChan = null;
    try {
        adbChan = SocketChannel.open(adbSockAddr);
        adbChan.configureBlocking(false);

        // if the device is not -1, then we first tell adb we're looking to talk
        // to a specific device
        setDevice(adbChan, device);

        write(adbChan, request);
    } finally {
        if (adbChan != null) {
            adbChan.close();
        }
    }
}

我们可以看到基本上,每个命令的执行,都是用了单独SocketChannel通过非阻塞方式执行,这样大大加强了并发,所以DDMS可以一边处理Logcat打印,显示堆信息,处理文件管理等等,有关NIO服务器的内容,Android开发网将着重分析MonitorThread.java这个文件,一起说下NIO的框架。