zoukankan      html  css  js  c++  java
  • Android开发进阶之NIO非阻塞包(六)

    有关Android NIO的相关内容,本次Android123整理并归类如下,为了让大家感觉NIOAndroid平台联系的紧密,这里我们结合ADT插件的重要开发工具DDMS中的源码进行分析。在android git中的sdk.git文件中,可以找到ddmlib这个文件夹。有关PC和手机的互通内核在这里使用了Java来完全实现。这里Android开发网一起帮助大家了解下PC同步软件的开发原理同时学习下Java中的New I/O技术。

       比较重要的代码段我们贴出,逐一分析,其他的网友可以直接预读源码:

       AdbHelper.java文件中

       public static SocketChannel open(InetSocketAddress adbSockAddr,
                Device device, int devicePort) //
    这是一个重载版本,主要是关联Device实例。
                throws IOException, TimeoutException, AdbCommandRejectedException {

            SocketChannel adbChan = SocketChannel.open(adbSockAddr); //构造SocketChannel对象,使用常规的open方法创建
            try {
                adbChan.socket().setTcpNoDelay(true); //
    设置TCP非延迟
                adbChan.configureBlocking(false); //
    非阻塞

                setDevice(adbChan, device); //本句和NIO没有多大关系,这句是指定具体的设备,比如模拟器,或Android手机的厂家代号,比如宏达电的以HTXXXXX这样的方式

                byte[] req = createAdbForwardRequest(null, devicePort); //设置端口转发,这句很关键,否则PC和手机通过USB是无法互通的。
                write(adbChan, req); //
    发送数据

                AdbResponse resp = readAdbResponse(adbChan, false); //读取收到的内容
                if (resp.okay == false) {
                    throw new AdbCommandRejectedException(resp.message);
                }

                adbChan.configureBlocking(true);
            } catch (TimeoutException e) { //
    一般要处理超时异常
                adbChan.close(); //
    释放channel句柄
                throw e;
            } catch (IOException e) { //
    处理常规的IO异常
                adbChan.close();
                throw e;
            }

            return adbChan;
        }

       有关读取ADB返回的报文方法

      static AdbResponse readAdbResponse(SocketChannel chan, boolean readDiagString)
                throws TimeoutException, IOException {

            AdbResponse resp = new AdbResponse();

            byte[] reply = new byte[4]; //创建4字节数组,主要检测成功与否,adb的协议是成功返回 okay,失败fail,等等。
            read(chan, reply); //
    读取具体的返回

            if (isOkay(reply)) { //判断是否成功
                resp.okay = true;
            } else {
                readDiagString = true; // look for a reason after the FAIL
                resp.okay = false;
            }

            // not a loop -- use "while" so we can use "break"
            try {
                while (readDiagString) {
                    // length string is in next 4 bytes
                    byte[] lenBuf = new byte[4];
                    read(chan, lenBuf); //
    读取一个字节数组,最终为了转为一个整形

                    String lenStr = replyToString(lenBuf); //字节数组转为String

                    int len;
                    try {
                        len = Integer.parseInt(lenStr, 16); //String
    转为整形,这里Android123提示,这种写法可能比较愚蠢,但是下面为Log输出提供了一点点的便利。
                    } catch (NumberFormatException nfe) {
                        Log.w("ddms", "Expected digits, got '" + lenStr + "': "
                                + lenBuf[0] + " " + lenBuf[1] + " " + lenBuf[2] + " "
                                + lenBuf[3]);
                        Log.w("ddms", "reply was " + replyToString(reply));
                        break;
                    }

                    byte[] msg = new byte[len];
                    read(chan, msg);

                    resp.message = replyToString(msg);
                    Log.v("ddms", "Got reply '" + replyToString(reply) + "', diag='"
                            + resp.message + "'");

                    break;
                }
            } catch (Exception e) {
                // ignore those, since it's just reading the diagnose string, the response will
                // contain okay==false anyway.
            }

            return resp;
        }

       有关PC上对Android手机屏幕截图的方法之一:

       static RawImage getFrameBuffer(InetSocketAddress adbSockAddr, Device device)
                throws TimeoutException, AdbCommandRejectedException, IOException {

            RawImage imageParams = new RawImage();
            byte[] request = formAdbRequest("framebuffer:"); //
    读取手机端adbd服务器的framebuffer调用返回的数组

            byte[] nudge = {
                0
            };
            byte[] reply;

            SocketChannel adbChan = null;
            try {
                adbChan = SocketChannel.open(adbSockAddr);
                adbChan.configureBlocking(false); //
    非阻塞

                setDevice(adbChan, device); //设置我们关系的设备

                write(adbChan, request); //发送framebuffer这个请求了

                AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */);
                if (resp.okay == false) {   //
    判断返回是否ok
                    throw new AdbCommandRejectedException(resp.message);
                }

                reply = new byte[4];
                read(adbChan, reply); //
    首先返回的是一个协议,目前分为两个版本,主要是兼容模式和标准的模式,兼容模式比较少见,在2.0以后几乎看不到了。部分早期的1.6或更老的T-Mobile G1会使用兼容模式,模式不同,输出的截图中的颜色编码方式略有不同。

                ByteBuffer buf = ByteBuffer.wrap(reply);
                buf.order(ByteOrder.LITTLE_ENDIAN); //
    小头字节顺序

                int version = buf.getInt(); //ByteBuffer直接转int的方法,比较方便不用自己从字节数组中构造,按位计算

                int headerSize = RawImage.getHeaderSize(version); //根据返回的adb截图协议版本判断将收到的字节大小

                reply = new byte[headerSize * 4]; //分配空间,具体大小需要看协议版本
                read(adbChan, reply);

                buf = ByteBuffer.wrap(reply); //reply数组实例化ByteBuffer
                buf.order(ByteOrder.LITTLE_ENDIAN); //
    注意字节序列,毕竟远端的adbd是工作在linux系统的手机上。

                if (imageParams.readHeader(version, buf) == false) { //判断是否有效,兼容这种截图协议。
                    Log.e("Screenshot", "Unsupported protocol: " + version);
                    return null;
                }

                Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size="
                        + imageParams.size + ", width=" + imageParams.width
                        + ", height=" + imageParams.height); //
    打印下截图的基本信息,比如bpp代表色深,size是需要分配dib图像的字节数组。比较原始,

                write(adbChan, nudge); //发送一个字节,代表准备接收字节数组了

                reply = new byte[imageParams.size]; //分配和图像大小一样的字节数组
                read(adbChan, reply); //
    接收图像字节数组,这里Android开发网提示大家对于Android 1.x可能为RGB565,分配大小为 wxhx2xsize ,而2.x以后基本上为32位的RGB8888,分配大小为wxhx4xsize

                imageParams.data = reply;
            } finally {
                if (adbChan != null) {
                    adbChan.close();
                }
            }

            return imageParams;
        }

      有关Android平台PC通过USBADB方式和手机同步原理和NIO相关技术,Android123明天继续讲解。

     

  • 相关阅读:
    【POJ 1958】 Strange Towers of Hanoi
    【HNOI 2003】 激光炸弹
    【POJ 3263】 Tallest Cow
    【POJ 2689】 Prime Distance
    【POJ 2777】 Count Color
    【POJ 1995】 Raising Modulo Numbers
    【POJ 1845】 Sumdiv
    6月16日省中集训题解
    【TJOI 2018】数学计算
    【POJ 1275】 Cashier Employment
  • 原文地址:https://www.cnblogs.com/cpcpc/p/2123004.html
Copyright © 2011-2022 走看看