说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

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

HTML文档下载 WORD文档下载 PDF文档下载
Android开发进阶之NIO非阻塞包(八)

作者:Android开发网


   在整个DDMS中体现Android NIO主要框架的要数MonitorThread.java这个文件了,有关PC和Android手机同步以及NIO非阻塞编程的精髓可以在下面的文件中充分体现出来。

  final class MonitorThread extends Thread {

    private static final int CLIENT_READY = 2;

    private static final int CLIENT_DISCONNECTED = 3;

    private volatile boolean mQuit = false;

    private ArrayList<Client> mClientList; //用一个数组保存客户端信息

    private Selector mSelector;

    private HashMap<Integer, ChunkHandler> mHandlerMap; //这里Android123提示大家,由于在多线程中concurrentHashMap效率比HashMap更安全高效,推荐使用并发库的这个替代版本。

    private ServerSocketChannel mDebugSelectedChan; //一个用于调试的服务器通道

    private int mNewDebugSelectedPort;

    private int mDebugSelectedPort = -1;

    private Client mSelectedClient = null;

    private static MonitorThread mInstance;

    private MonitorThread() {
        super("Monitor");
        mClientList = new ArrayList<Client>();
        mHandlerMap = new HashMap<Integer, ChunkHandler>();

        mNewDebugSelectedPort = DdmPreferences.getSelectedDebugPort();
    }

    static MonitorThread createInstance() {  //创建实例
        return mInstance = new MonitorThread();
    }

    static MonitorThread getInstance() { //获取实例
        return mInstance;
    }

    synchronized void setDebugSelectedPort(int port) throws IllegalStateException { //设置调试端口号
        if (mInstance == null) {
            return;
        }

        if (AndroidDebugBridge.getClientSupport() == false) {
            return;
        }

        if (mDebugSelectedChan != null) {
            Log.d("ddms", "Changing debug-selected port to " + port);
            mNewDebugSelectedPort = port;
            wakeup(); //这里用来唤醒所有的Selector
        } else {
            // we set mNewDebugSelectedPort instead of mDebugSelectedPort so that it's automatically
            mNewDebugSelectedPort = port;
        }
    }

    synchronized void setSelectedClient(Client selectedClient) {
        if (mInstance == null) {
            return;
        }

        if (mSelectedClient != selectedClient) {
            Client oldClient = mSelectedClient;
            mSelectedClient = selectedClient;

            if (oldClient != null) {
                oldClient.update(Client.CHANGE_PORT);
            }

            if (mSelectedClient != null) {
                mSelectedClient.update(Client.CHANGE_PORT);
            }
        }
    }

    Client getSelectedClient() {
        return mSelectedClient;
    }

    boolean getRetryOnBadHandshake() {
        return true; // TODO? make configurable
    }

    Client[] getClients() {
        synchronized (mClientList) {
            return mClientList.toArray(new Client[0]);
        }
    }

    synchronized void registerChunkHandler(int type, ChunkHandler handler) {
        if (mInstance == null) {
            return;
        }

        synchronized (mHandlerMap) {
            if (mHandlerMap.get(type) == null) {
                mHandlerMap.put(type, handler);
            }
        }
    }

    @Override
    public void run() { //本类的主要线程
        Log.d("ddms", "Monitor is up");

        try {
            mSelector = Selector.open();
        } catch (IOException ioe) {
            Log.logAndDisplay(LogLevel.ERROR, "ddms",
                    "Failed to initialize Monitor Thread: " + ioe.getMessage());
            return;
        }

        while (!mQuit) {

            try {
                synchronized (mClientList) {
                }

                try {
                    if (AndroidDebugBridge.getClientSupport()) {
                        if ((mDebugSelectedChan == null ||
                                mNewDebugSelectedPort != mDebugSelectedPort) &&
                                mNewDebugSelectedPort != -1) {
                            if (reopenDebugSelectedPort()) {
                                mDebugSelectedPort = mNewDebugSelectedPort;
                            }
                        }
                    }
                } catch (IOException ioe) {
                    Log.e("ddms",
                            "Failed to reopen debug port for Selected Client to: " + mNewDebugSelectedPort);
                    Log.e("ddms", ioe);
                    mNewDebugSelectedPort = mDebugSelectedPort; // no retry
                }

                int count;
                try {
                    count = mSelector.select();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    continue;
                } catch (CancelledKeyException cke) {
                    continue;
                }

                if (count == 0) {
                    continue;
                } //这里代码写的不是很好,Android开发网提示大家因为这个NIO是DDMS工作在PC端的还不明显,这样轮训的在一个while中,效率不是很高,CPU很容易占用率很高。

                Set<SelectionKey> keys = mSelector.selectedKeys();
                Iterator<SelectionKey> iter = keys.iterator(); //使用迭代器获取这个选择键

                while (iter.hasNext()) {
                    SelectionKey key = iter.next();
                    iter.remove();

                    try {
                        if (key.attachment() instanceof Client) { //判断收到的key的附件是否是Client的实例
                            processClientActivity(key);
                        }
                        else if (key.attachment() instanceof Debugger) { //如果是Debug实例
                            processDebuggerActivity(key);
                        }
                        else if (key.attachment() instanceof MonitorThread) {
                            processDebugSelectedActivity(key);
                        }
                        else {
                            Log.e("ddms", "unknown activity key");
                        }
                    } catch (Exception e) {
                        Log.e("ddms", "Exception during activity from Selector.");
                        Log.e("ddms", e);
                    }
                }
            } catch (Exception e) {
                Log.e("ddms", "Exception MonitorThread.run()");
                Log.e("ddms", e);
            }
        }
    }

    int getDebugSelectedPort() {
        return mDebugSelectedPort;
    }

    private void processClientActivity(SelectionKey key) {
        Client client = (Client)key.attachment();

        try {
            if (key.isReadable() == false || key.isValid() == false) {
                Log.d("ddms", "Invalid key from " + client + ". Dropping client.");
                dropClient(client, true /* notify */);
                return;
            }

            client.read();

            JdwpPacket packet = client.getJdwpPacket();
            while (packet != null) {
                if (packet.isDdmPacket()) {
                    // unsolicited DDM request - hand it off
                    assert !packet.isReply();
                    callHandler(client, packet, null);
                    packet.consume();
                } else if (packet.isReply()
                        && client.isResponseToUs(packet.getId()) != null) {
                    // reply to earlier DDM request
                    ChunkHandler handler = client
                            .isResponseToUs(packet.getId());
                    if (packet.isError())
                        client.packetFailed(packet);
                    else if (packet.isEmpty())
                        Log.d("ddms", "Got empty reply for 0x"
                                + Integer.toHexString(packet.getId())
                                + " from " + client);
                    else
                        callHandler(client, packet, handler);
                    packet.consume();
                    client.removeRequestId(packet.getId());
                } else {
                    Log.v("ddms", "Forwarding client "
                            + (packet.isReply() ? "reply" : "event") + " 0x"
                            + Integer.toHexString(packet.getId()) + " to "
                            + client.getDebugger());
                    client.forwardPacketToDebugger(packet);
                }

                packet = client.getJdwpPacket();
            }
        } catch (CancelledKeyException e) { //注意正确处理这个异常
            dropClient(client, true /* notify */);
        } catch (IOException ex) {
            dropClient(client, true /* notify */);
        } catch (Exception ex) {
            Log.e("ddms", ex);

            dropClient(client, true /* notify */);

            if (ex instanceof BufferOverflowException) { //可能存在缓冲区异常
                Log.w("ddms",
                        "Client data packet exceeded maximum buffer size "
                                + client);
            } else {
                // don't know what this is, display it
                Log.e("ddms", ex);
            }
        }
    }

    private void callHandler(Client client, JdwpPacket packet,
            ChunkHandler handler) {

        // on first DDM packet received, broadcast a "ready" message
        if (!client.ddmSeen())
            broadcast(CLIENT_READY, client);

        ByteBuffer buf = packet.getPayload();
        int type, length;
        boolean reply = true;

        type = buf.getInt();
        length = buf.getInt();

        if (handler == null) {
            // not a reply, figure out who wants it
            synchronized (mHandlerMap) {
                handler = mHandlerMap.get(type);
                reply = false;
            }
        }

        if (handler == null) {
            Log.w("ddms", "Received unsupported chunk type "
                    + ChunkHandler.name(type) + " (len=" + length + ")");
        } else {
            Log.d("ddms", "Calling handler for " + ChunkHandler.name(type)
                    + " [" + handler + "] (len=" + length + ")");
            ByteBuffer ibuf = buf.slice();
            ByteBuffer roBuf = ibuf.asReadOnlyBuffer(); // enforce R/O
            roBuf.order(ChunkHandler.CHUNK_ORDER);
            synchronized (mClientList) {
                handler.handleChunk(client, type, roBuf, reply, packet.getId());
            }
        }
    }

    synchronized void dropClient(Client client, boolean notify) {
        if (mInstance == null) {
            return;
        }

        synchronized (mClientList) {
            if (mClientList.remove(client) == false) {
                return;
            }
        }
        client.close(notify);
        broadcast(CLIENT_DISCONNECTED, client);

        /*
         * http://forum.java.sun.com/thread.jspa?threadID=726715&start=0
         * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5073504
         */
        wakeup();
    }

    /*
     * Process activity from one of the debugger sockets. This could be a new
     * connection or a data packet.
     */
    private void processDebuggerActivity(SelectionKey key) {
        Debugger dbg = (Debugger)key.attachment();

        try {
            if (key.isAcceptable()) { //处理Server响应这个事件
                try {
                    acceptNewDebugger(dbg, null);
                } catch (IOException ioe) {
                    Log.w("ddms", "debugger accept() failed");
                    ioe.printStackTrace();
                }
            } else if (key.isReadable()) { //如果是收到的数据,则可读取
                processDebuggerData(key);
            } else {
                Log.d("ddm-debugger", "key in unknown state");
            }
        } catch (CancelledKeyException cke) { //记住,NIO处理这个异常,很多入门的开发者很容易忘记
            // key has been cancelled we can ignore that.
        }
    }

     private void acceptNewDebugger(Debugger dbg, ServerSocketChannel acceptChan) //这里用到了阻塞方式
            throws IOException {

        synchronized (mClientList) {
            SocketChannel chan;

            if (acceptChan == null)
                chan = dbg.accept();
            else
                chan = dbg.accept(acceptChan);

            if (chan != null) {
                chan.socket().setTcpNoDelay(true);

                wakeup();

                try {
                    chan.register(mSelector, SelectionKey.OP_READ, dbg);
                } catch (IOException ioe) {
                    // failed, drop the connection
                    dbg.closeData();
                    throw ioe;
                } catch (RuntimeException re) {
                    // failed, drop the connection
                    dbg.closeData();
                    throw re;
                }
            } else {
                Log.w("ddms", "ignoring duplicate debugger");
            }
        }
    }

    private void processDebuggerData(SelectionKey key) {
        Debugger dbg = (Debugger)key.attachment();

        try {
            dbg.read();

            JdwpPacket packet = dbg.getJdwpPacket();
            while (packet != null) {
                Log.v("ddms", "Forwarding dbg req 0x"
                        + Integer.toHexString(packet.getId()) + " to "
                        + dbg.getClient());

                dbg.forwardPacketToClient(packet);

                packet = dbg.getJdwpPacket();
            }
        } catch (IOException ioe) {
            Log.d("ddms", "Closing connection to debugger " + dbg);
            dbg.closeData();
            Client client = dbg.getClient();
            if (client.isDdmAware()) {
                   Log.d("ddms", " (recycling client connection as well)");

                    client.getDeviceImpl().getMonitor().addClientToDropAndReopen(client,
                        IDebugPortProvider.NO_STATIC_PORT);
            } else {
                Log.d("ddms", " (recycling client connection as well)");
                // we should drop the client, but also attempt to reopen it.
                // This is done by the DeviceMonitor.
                client.getDeviceImpl().getMonitor().addClientToDropAndReopen(client,
                        IDebugPortProvider.NO_STATIC_PORT);
            }
        }
    }

    private void wakeup() {
        mSelector.wakeup();
    }

    synchronized void quit() {
        mQuit = true;
        wakeup();
        Log.d("ddms", "Waiting for Monitor thread");
        try {
            this.join();
            // since we're quitting, lets drop all the client and disconnect
            // the DebugSelectedPort
            synchronized (mClientList) {
                for (Client c : mClientList) {
                    c.close(false /* notify */);
                    broadcast(CLIENT_DISCONNECTED, c);
                }
                mClientList.clear();
            }

            if (mDebugSelectedChan != null) {
                mDebugSelectedChan.close();
                mDebugSelectedChan.socket().close();
                mDebugSelectedChan = null;
            }
            mSelector.close();
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        mInstance = null;
    }

    synchronized void addClient(Client client) {
        if (mInstance == null) {
            return;
        }

        Log.d("ddms", "Adding new client " + client);

        synchronized (mClientList) {
            mClientList.add(client);

            try {
                wakeup();

                client.register(mSelector);

                Debugger dbg = client.getDebugger();
                if (dbg != null) {
                    dbg.registerListener(mSelector);
                }
            } catch (IOException ioe) {
                // not really expecting this to happen
                ioe.printStackTrace();
            }
        }
    }

    /*
     * Broadcast an event to all message handlers.
     */
    private void broadcast(int event, Client client) {
        Log.d("ddms", "broadcast " + event + ": " + client);

        /*
         * The handler objects appear once in mHandlerMap for each message they
         * handle. We want to notify them once each, so we convert the HashMap
         * to a HashSet before we iterate.
         */
        HashSet<ChunkHandler> set;
        synchronized (mHandlerMap) {
            Collection<ChunkHandler> values = mHandlerMap.values();
            set = new HashSet<ChunkHandler>(values);
        }

        Iterator<ChunkHandler> iter = set.iterator();
        while (iter.hasNext()) {
            ChunkHandler handler = iter.next();
            switch (event) {
                case CLIENT_READY:
                    try {
                        handler.clientReady(client);
                    } catch (IOException ioe) {
                        // Something failed with the client. It should
                        // fall out of the list the next time we try to
                        // do something with it, so we discard the
                        // exception here and assume cleanup will happen
                        // later. May need to propagate farther. The
                        // trouble is that not all values for "event" may
                        // actually throw an exception.
                        Log.w("ddms",
                                "Got exception while broadcasting 'ready'");
                        return;
                    }
                    break;
                case CLIENT_DISCONNECTED:
                    handler.clientDisconnected(client);
                    break;
                default:
                    throw new UnsupportedOperationException();
            }
        }

    }

    /**
     * Opens (or reopens) the "debug selected" port and listen for connections.
     * @return true if the port was opened successfully.
     * @throws IOException
     */
    private boolean reopenDebugSelectedPort() throws IOException {

        Log.d("ddms", "reopen debug-selected port: " + mNewDebugSelectedPort);
        if (mDebugSelectedChan != null) {
            mDebugSelectedChan.close();
        }

        mDebugSelectedChan = ServerSocketChannel.open();
        mDebugSelectedChan.configureBlocking(false); // required for Selector

        InetSocketAddress addr = new InetSocketAddress(
                InetAddress.getByName("localhost"), //$NON-NLS-1$
                mNewDebugSelectedPort);
        mDebugSelectedChan.socket().setReuseAddress(true); // enable SO_REUSEADDR

        try {
            mDebugSelectedChan.socket().bind(addr);
            if (mSelectedClient != null) {
                mSelectedClient.update(Client.CHANGE_PORT);
            }

            mDebugSelectedChan.register(mSelector, SelectionKey.OP_ACCEPT, this);

            return true;
        } catch (java.net.BindException e) {
            displayDebugSelectedBindError(mNewDebugSelectedPort);

            // do not attempt to reopen it.
            mDebugSelectedChan = null;
            mNewDebugSelectedPort = -1;

            return false;
        }
    }

    /*
     * We have some activity on the "debug selected" port. Handle it.
     */
    private void processDebugSelectedActivity(SelectionKey key) {
        assert key.isAcceptable();

        ServerSocketChannel acceptChan = (ServerSocketChannel)key.channel();

        /*
         * Find the debugger associated with the currently-selected client.
         */
        if (mSelectedClient != null) {
            Debugger dbg = mSelectedClient.getDebugger();

            if (dbg != null) {
                Log.d("ddms", "Accepting connection on 'debug selected' port");
                try {
                    acceptNewDebugger(dbg, acceptChan);
                } catch (IOException ioe) {
                    // client should be gone, keep going
                }

                return;
            }
        }

        Log.w("ddms",
                "Connection on 'debug selected' port, but none selected");
        try {
            SocketChannel chan = acceptChan.accept();
            chan.close();
        } catch (IOException ioe) {
            // not expected; client should be gone, keep going
        } catch (NotYetBoundException e) {
            displayDebugSelectedBindError(mDebugSelectedPort);
        }
    }

    private void displayDebugSelectedBindError(int port) {
        String message = String.format(
                "Could not open Selected VM debug port (%1$d). Make sure you do not have another instance of DDMS or of the eclipse plugin running. If it's being used by something else, choose a new port number in the preferences.",
                port);

        Log.logAndDisplay(LogLevel.ERROR, "ddms", message);
    }
}

  从上面来看Android的开源代码有关PC上的写的不是很好,很多实现的地方都是用了严重的缝缝补补方式解决,有些习惯不是很到位,有关本NIO例子由于涉及的项目对象多,理解需要网友深入分析DDMS源码中的每个对象。细节写的不是很理想,Android123推荐大家,画出UML后再分析更清晰。

《近匠》机智云CEO黄灼:跨越智能硬件的“鸿沟” 智能手机≠智能家居!我们要的究竟是什么? 亚信大数据事业部总经理张灏:打通各行业数据壁垒 让大数据变现畅通无阻 Web App和Native App不是生死之争,而是可以和平共处! 微信之父张小龙说微信坚持“去中心化”,这样真的好吗? 亚信CFO武军谈进军海外市场成功经验 前瞻性思维是开路先峰 Swift,任重而道远! DevOps系统的变迁 玩转Docker镜像 “扫描建模”速建AR应用 Vuforia 4.0 SDK更新 硅谷里的外星人:纵观Reddit十年风雨路 不见不散 Cloud Foundry Meetup活动将首次走进杭州 独立开发者:新手做2D手游该用哪些工具? 求安全化危机!Uber研发生物识别技术、聘请前亚马逊运营 JavaScript社区开发者调查:服务端JS盛行 AngularJS使用者最多 去中心化、去中介化,微信商业化路径清晰了吗? 微信企业号认证简化了,你造吗? 专访瀚思安信联合创始人:大数据技术助力企业实现主动智能防御 挑选IBM Bluemix作为云平台的10大理由 10年技术积累成就极光压缩引擎,欧朋流量宝5.0面世 【图文实录】12月19日CTO俱乐部走进杭州 mlpack:可伸缩C++机器学习库 本地项目托管将死?类GitHub站点永存! 2014年讨论最多的编程语言:JavaScript称霸 移动Web应用UI框架大比拼:Ionic vs. Famo.us vs. F7 vs. OnsenUI 面包旅行CTO薛亮:做旅游与社交有机结合的先行者 盘点开发者最喜爱的Swift技巧 2017年,开发者还能从移动广告中收获什么? 《近匠》茄子快传,让设备更好地连接 面向移动应用程序的DevOps五大挑战和十个最佳实践 Ruby 2.2.0发布,支持回收Symbol类型对象 使用jdom遇到的莫名其妙的问题(有关Element.getChildren()返回类型?) 运行速度的问题如何解决? 对ISO98版的c++支持最好的编译器是什么(unix\win\dos)? sqlserver网络备份是错误码42000。详情请看。。。 急!!请问如何通过程序检测一个系统中的Office版本(比如:中文版,英文版) 请问有人知道上海伍尔特国际咨询公司的朋友嘛 ? 怎样在信件里面自动添加信息? 2万元寻人力资源管理软件 友情链接,我的网站http://fullstrong.myetang.com/ 有没有人统计过windows有多少个api加上shell呢? 请问:winsock的SendData的调用,在收发email时改如何设置参数 请问gdk和gtk的函数库是怎么按装的? 搞不定了,7456..来回切换窗口状态的问题, 有源码 友情链接,我的网站http://fullstrong.myetang.com/ 请问RTDB(实时数据库和商用数据库的区别) 各位高手,请问在Tomcat下怎么解决中文问题? XML如何实现曲线图、饼图、梯形图的表示? “红萝卜的胳膊白萝卜的腿”谁听过? 问一个语法的问题? 读入文本的回车和换行为什么都没有了 类似HTML为扩展名的有哪几种文件 安装php+Mysql+Apache时出现的一个小问题,请高手指教! 取url中?后参数的javascript函数是什么? 怎么样来控制声道,如左声道,右声道,立体声? 简单问题,能介绍一下dual吗?? 新操作系统,老编程工具 这样能兼容吗? applet请教 衷心祝愿正在找工作的朋友们心想事成 浪费了几百份了,从来没人回答这个问题,窝气阿,up以下也好啊?????? 米卢是神奇的,中国队更神奇! 有谁知道哪里可以下载PDF Reference Manual中文版? 请教各位大虾! 怎样能把oracle数据库中的所有用户表的结构以及主键外键信息导出为sql 脚本? 踢得真不公平,真是21人踢我们一个人! 友情链接,我的网站http://fullstrong.myetang.com/ VB里面怎么编译出,不用安装的运行程序,请问在那里设置?(上限5分,人人有分)? 哪位大师知道在VC中怎样实现视频捕捉功能 有谁知道mp3的压缩和解压缩算法 问一下关于文件图标的问题。 pb6.5,win2000中文板,Oracle817.在oracle中连接数据库正确。在pb中连接数据库错误。什么内存出错,还有pbo7360.dll acess error之类的错 急!!请问如何将扩展名为PLB的文件转换为SQL文件 关于datagrid的selecteditem事件 谁能告诉我如何给回答对的人加分呀,散分啦 有谁知道哪里可以下载PDF Reference Manual中文版? 文件上传,然后把文件中的数据写入数据库,怎样做到。 问一个很菜的问题 100分在线等待:请介绍resin 如何在listview在作模糊查询。100分 ODBC下正确,BDE下出错?为什么?分数不够可以再加 项目中的角色 vb中怎样终止一个正在运行的应用程序? 噪声对人体有什么危害? 380v的电能电死人吗 提升重物的机械效率跟滑轮组机械效率、拉力机械效率什么的有什么区别没有? 噪声对人体的损害有哪些 内蒙古阿拉善银星风力发电有限公司 翻译成蒙古语是什么 在提升相同重物时的拉力是否是影响滑轮组机械效率的因素? 刹车后汽车做匀减速直线运动,最后停下来,那么,它在前半路程和后半路程所花费的时间之比是 在前一半时间与后一半时间的平均速度之比是 各种糖的化学式越多越好! 地理信息系统(GIS)应用现状及发展趋势.地理信息系统(GIS)应用现状及发展趋势?各位哥哥姐姐,小弟考研问题(最后一道大题),希望知道的能尽快给我一个答复,尽量详细点, 概率论 应用问题 刹车后汽车做匀减速直线运动到停止,则它在前一半时间与后一半时间的平均速度之比? 糖的化学式 概率论在其他学科中有哪些应用? 室内照明那种牌子的节能灯好?选购节能灯应该注意那些问题?无奈 GIS的应用领域有哪些? 火车轨道重力与向心力合力方向我们学过,在斜面上的物体受力平衡时,其重力与支持力的合力与摩擦力平衡,所以重力与支持力的合力的方向应平行于斜面向下.但书上却说在一侧高的火车轨道 现在家居照明是继续选择普通节能灯还是LED灯?想从照明的视光学效果和健康程度、LED的市场成熟度做一个了解. 柠檬酸钠化学式是什么?吃了对人体有害吗? 火车轨道重力与向心力合力方向是怎样的? 多大的电流才能电死人 gis的应用领域有多宽,有多大的前途? 一盏20W的节能灯亮度相当于一盏100W的白炽灯若它们都正常发光10小时,节能灯与白炽灯相比,了节约用电多少千瓦时 最近听说有个小白龙照明企业节能灯品牌,怎么样?现在的节能灯产品怎样~ gis的应用有哪些?GIS的发展使? 一只100W的白炽灯泡,价格为2元;一支20W的节能灯,价格为12元,一只100W的白炽灯泡,价格为2元;一支20W的节能灯,价格为12元,但能提供与100W白炽灯泡一样的亮度.假设每盏灯每天使用2h,每年以360天 电压大能电死人还是电流大能电死人 偏航器用英语怎么说 20W节能灯相当于白炽灯多少W上面说20W节能灯亮度=100W白炽灯,可是回家装上感觉根本就不可能有100W白炽灯的亮度嘛,顶多和40W的白炽灯差不多了,这到底是怎么回事,请教一下! 说是电流电死人5W功率的小灯泡 和2V电压的电池 有手去摸为什么没感觉 电流都2.5A了?安全不是说50mA吗 求将表格中的化学式转换成下面的样子. 氯化钠溶液中混有杂质碳酸钠,用盐酸去除,方法是?z操作方法是? 请举例说明 几个高一化学式的转换比较基础的在线等很急!金属--成碱性氧化物(互换)碱性氧化物--碱 (有3个)碱--盐 1个盐--盐酸--盐酸性氧化物--酸 (互换)非金属--酸性氧化物 1个能写出几个方程式 噪音的来源主要有哪些?对人体有什么危害? 物理变化中是不是一定不可能存在化学变化? gis在煤矿上的应用有哪些 汽车刹车后做匀减速直线运动,经3秒后停止运动,那么,在这连续的三个1秒内汽车通过的位移之是 匀减速直线运动求位移之比! 2012年10月1日起,我国分阶段逐步禁止进口和销售普通照明白炽灯,并将在2018年淘汰白炽灯.节能灯比同光效的白炽灯节能60%~80%,且使用寿命长.一只标有“220V 60W”的白炽灯,正常发光时通过灯丝 初三酸碱盐,转换, 汽车以16米每秒的速度运动,遇到紧急情况刹车,刹车过程视为匀减速直线运动开始刹车后两秒内速度变为8米每秒,我已经算出来加速度为-4米每秒,求汽车停下前3秒内通过的位移.还有一个小时 机械噪音 人体 危害我是开数控通快2020机床的,机床噪音每天很大,请问它对人体的损害有哪些?同时要防止补充什么营养》谢谢! GIS的应用范围有多广?谁给点具体的例子 (多选)功率比为3:2的两辆汽车在水平路上匀速行驶,相等的时间内通过的路程之比为2:1,则( ) A.两辆汽车的牵引力之比是1:2 B.两辆汽车的牵引力之比是3:4 C.两辆汽车做功之比是3:2 D. 光合作用与有氧呼吸的区别与联系 GIS的应用GIS可以用来( )A.获取灾区数字信息 B.在救灾中导航 C.对灾害发生地定位 D.建立救灾决策指挥系统 汽车刹车后做匀减速直线运动,最后2秒内位移为5米,根据以上条件,可以求出汽车刹车过程中的( )C.所用时间D.通过的总位移 36题,关于美国农业初一地理题 gis在物流中的应用 机械和功 题是这样的:b点在五带中的热带,在 气压带控制下.还有:1.一年中,5三个月是1南半球的春季 2北半球的冬季 3南半球的秋季 4北半球的秋季 b点在热带. 地理信息系统的应用 15平米的卧室为什么使用100W的节能灯还是很暗? 为什么红磷在验证空气中氧气含量时,红磷含量要过量 100W的太阳能电池板一般是多少A电流?12/24 100W节能灯的光通量是多少哦大概是多少 汽车刹车后作匀减速运动,最后停了下来,在刹车过程中,汽车前半程的平均速度与后半程的平均速度之比是?希望有准确的解释 我该把这份文件发给谁?英语怎么说给对方写e-mail的 100w节能灯能照2.5米高多少平方 英语翻译"中广核"三字,是否要翻译? 既能溶于水又能溶于酸的碱是A.Cu(OH)2 B.Na2CO3 C.CaCO3 D.NaOH 并且写出原因
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘