serviceRepaints是如何实现强制刷屏的!

原创 2007年09月27日 14:56:00
SUN在它的API里,说过。
Forces any pending repaint requests to be serviced immediately. This method blocks until the pending requests have been serviced. If there are no pending repaints, or if this canvas is not visible on the display, this call does nothing and returns immediately
强制让任何有repaint的请求立即得到服务。这个方法将阻塞,一直到此请求被“服务”掉 。如果没有repaint请求,或者当前canvas不可视,这个调用将立即返回,不做任何事。

比如:
当我们在一个线程里,设置了某些要画的object的坐标值。调用了repaint而没有调用serviceRepaint的画,那么,系统会从隶属于repaint的队列里进行区域运算,得到一个多次请求复合后的RECT,然后进行处理。那么是吗时候能得到处理呢?不知道。那要看系统情况,这个问题,我稍后再说。
那么调用了serviceRepaints呢,最后的结果是,系统会理解调用Paint。进行刷屏操作。

我们来看一下源码:

  1. 在Canvas中的代码是:
    public final void serviceRepaints() {
            Display d = currentDisplay;
            if (d != null) {
                d.serviceRepaints(this);
            }
        }
    可见,canvas调用的是Display的serviceRepaints
  2. 在Display的代码是:
    void serviceRepaints(Displayable d) {
            synchronized (LCDUILock) {
                if (paintSuspended || !hasForeground || d != current) {
                    return;
                }
            }

            eventHandler.serviceRepaints();
        }
    不可视,无repaint请求,currentDisplay不一样,都将立即返回(不理解的将在以后加以说明)
  3. 那么,现在serviceRepaints的请求,将要被eventHandler处理。
    那么,我们来看看eventHandler。
    eventHandler是由Display来通过class.forName来加载的
    -------------------------
     private static EventHandler getEventHandler() {

            String n = Configuration.getProperty(
                "com.sun.midp.lcdui.eventHandler");

            try {
                return (EventHandler) (Class.forName(n)).newInstance();
            } catch (Exception e) { }

            if (Configuration.getProperty("microedition.configuration") != null) {
                try {
                    return (EventHandler) (Class.forName(
                        "com.sun.midp.lcdui.AutomatedEventHandler")).newInstance();
                } catch (Exception e) { }

                try {
                    return (EventHandler) (Class.forName(
                        "com.sun.midp.lcdui.DefaultEventHandler")).newInstance();
                } catch (Exception e) { }

                throw new Error("Unable to establish EventHandler");
            }

            try {
                return (EventHandler)
                    (Class.forName(
                        "com.sun.midp.lcdui.AWTEventHandler")).newInstance();
            } catch (Exception e) { }

            throw new Error("Unable to establish EventHandler");
        }
    -------------------------------
  4. 现在焦点又要到EventHandler了,看他是如何处理serviceRepaints的吧。
    public void serviceRepaints() {
            try {
                eventQueue.serviceRepaints();
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
  5. oh,MyGod,现在又要转换焦点到eventQuene,那么再让我们来看看这个eventQuene是怎么处理serviceRepaints的。
    class EventQueue {
            /** The latest vm event */
            int vmEvent;
            /** The parent Display of the next Displayable. */
            Display parentOfNextScreen;
            /** The next displayable to show */
            Displayable nextScreen;
            /** A flag to process all call serially's */
            boolean callSeriallyPending;
            /** A flag to perform an invalidation of a Form */
            boolean invalidatePending;
            /** An Item can be the cause of an invalidation */
            Item invalidItem;
            /** An Item whose state has changed */
            Item changedItem;
            /** The dirty region for any pending repaint */
            int paintX1, paintY1, paintX2, paintY2;
            /** The optional target for the repaint */
            Object paintTarget;
            /** The lock for manipulating queue data */
            Object qLock;

            /**
             * Create a new default EventQueue
             */
            public EventQueue() {
                qLock = new Object();
                paintX1 = paintY1 = paintX2 = paintY2 = -1;
            }

            /**
             * Service any pending repaints. If there is a pending
             * repaint, process it immediately, otherwise return.
             */
            public void serviceRepaints() {
                int x1, y1, x2, y2;
                Object target;

                synchronized (qLock) {
                    if (paintX1 == -1) {
                        return;
                    }
                    x1 = paintX1;
                    y1 = paintY1;
                    x2 = paintX2;
                    y2 = paintY2;
                    target = paintTarget;
                    paintX1 = paintY1 = paintX2 = paintY2 = -1;
                    paintTarget = null;
                }

                repaintScreenEvent(x1, y1, x2, y2, target);
            }
     void repaintScreenEvent(int x1, int y1, int x2, int y2, Object target) {
            try {
                synchronized (eventLock) {
                    displayManager.repaint(x1, y1, x2, y2, target);
                }
            } catch (Throwable t) {
                handleThrowable(t);
            }
        }
  6. 现在又要转移到DisplayManager上,这个类,我们再MIDP2。0里从来没有碰到过,所以,可以断定那个一定是一个厂商扩展包。现在开始找,我找,我找。。。
    在com/sun/midp/lcdui/DisplayEvents.java里有一个接口类。他定义了一个接口。
    void repaint(int x1, int y1, int x2, int y2, Object target);(5个参数
    肯定有一个扩展的类来实现了这个接口,我再找,我找,我找。。
    public interface DisplayAccess extends DisplayEvents,我再找DisplayAccess,
  7. Display中有一个内部类:DisplayAccessor,这个类实现了DisplayAccess接口。
  8. 这个内部类里是如何实现repaint的呢?
    public void repaint(int x1, int y1, int x2, int y2, Object target) {
                           Display.this.repaint(x1, y1, x2, y2, target);
            }
    可见,最后还是调用的Display的repaint方法,最后绕啊,绕啊,最后还是绕到Display这里了。
  9. OK,那么最后让我们来看看Display的repaint方法。
     void repaint(int x1, int y1, int x2, int y2, Object target) {
            Displayable currentCopy = null;

            synchronized (LCDUILock) {
                if (paintSuspended || !hasForeground) {
                    return;
                }
                currentCopy = current;
            }

            if (currentCopy == null) {
                return;
            }

            screenGraphics.reset(x1, y1, x2, y2);
            current.callPaint(screenGraphics, target);
            refresh(x1, y1, x2, y2);
        }
  10. current.callPaint是在Displayabe里实现的。

  11. Canvas重写了callPaint
    void callPaint(Graphics g, Object target) {
            super.callPaint(g, target);

            if (g.getClipY() + g.getClipHeight() <= viewport[Y]) {
                return;
            }

            // We prevent the Canvas from drawing outside of the
            // allowable viewport - such as over the command labels
            g.clipRect(viewport[X], viewport[Y],
                       viewport[WIDTH],
                       viewport[HEIGHT]);

            synchronized (Display.calloutLock) {
                g.translate(viewport[X], viewport[Y]);
                try {
                    paint(g); //这个就是最后调用srviceRePaint后的效果。
                } catch (Throwable t) {
                    Display.handleThrowable(t);
                }
                g.translate(-viewport[X], -viewport[Y]);
            }
        }
  12. 找到这里,似乎好象找到了答案,其实还没有,在Display中,有两个同步锁:
    /** Static lock object for LCDUI package */
        static final Object LCDUILock = new Object();

        /** Static lock object for making calls into application code */
        static final Object calloutLock = new Object();
    这两个同步锁,一个是用来同步paint的操作。一个是用来同步诸多调用的,比如,系统通知KVM的
     void callKeyPressed(int keyCode) {
            if (allowKey(keyCode)) {
                synchronized (Display.calloutLock) {/保证系统底层发来的消息不会紊乱。
                    try {
                        this.keyPressed(keyCode);
                    } catch (Throwable t) {
                        Display.handleThrowable(t);
                    }
                }
            }
        }
  13. 因为这个问题,很多人都在争论,我想我就把sun的实现,理理,整理在这里,不过,sun为了实现扩展,模块化,我靠,真是绕了很多的弯,不过我说这个不是说sun的不好,而是让我费了很大的劲才找到。以上说的仅供你参考。
  14. 在Display里有几个类和方法是很需要注意的。
    • DisplayAccessor
    • DisplayManagerImpl
    • 同步锁。
      有了这些跟硬件结合机密的类,再加上native的API,一个完整的能给我们来操纵的世界就展现出来了,
  15. 最后,欢迎各位给我加评论。指出我的错误。
  16. 送大家一个问题:如果在KEYPRESS里调用serviceRepaint会怎么样?
我贴一段SUN的comment,估计会你有所收获的。嘿嘿
--------------------------------
Warning: This method blocks until the call to the application's paint() method returns. The application has no control over which thread calls paint(); it may vary from implementation to implementation. If the caller of serviceRepaints() holds a lock that the paint() method acquires, this may result in deadlock. Therefore, callers of serviceRepaints() must not hold any locks that might be acquired within the paint() method. The Display.callSerially() method provides a facility where an application can be called back after painting has completed, avoiding the danger of deadlock.
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

《网上订餐系统》开发全程回忆

一、需求分析          随着信息经济的发展,许多上班族因工作繁忙导致就餐时间紧凑,而没法享受各种美味。传统的订餐方式过于乏味。而不能满足当今社会快速的生活节凑。然而,把餐饮与互联网结合起来正...

mybatis学习笔记

1、resultMap属于直接映射,可以把结果集中的数据库字段与实体类中的属性一一对应,这样通过select语句得到的结果就会准确的对上号 2、resultclass属于隐身映射,虽然你指定resu...

mysql+mybatis 集合查询配置

mybatis映射配置文件: 主要:

装sql server sp4时,出现以前进行的程序安装创建了挂起的文件操作.运行程序之前,必须重新起动计算机

在安装Sql或sp补丁的时候系统提示之前有挂起的安装操作,要求重启,这里往往重启无用,解决办法:  到HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Contr...

linux 安装中文支持包及中文字符集配置

由于某些原因系统安装时未安装中文支持,导致后续应用出现中文方块乱码现象,解决方法很简单,当然不是重装,只需以下三步即可搞定。 1、安装中文包: #yum -y groupinstall chine...

floyd算法

最近开始学算法,感觉存在电脑总有些不安全,没办法,这不是自己的电脑。    对于最短路径算法,floyd的算法的代码无疑是最容易写出来的,代码量少,而且很简洁。    首先要明确floyd算法的思想:...

Java开发工具常识

打开 Eclipse -> Window -> Perferences -> Java -> Editor -> Content Assist,在右边最下面一栏找到 auto-Activation ...

SqlSessionFactory创建SqlSession测试mybatis的sql

SqlSessionFactory创建SqlSession测试mybatis映射文件的sql package com.xuan.mybatis.first; import java.io.IOExc...

Linux下字符集的安装

目前环境中经常会遇到编码转化的问题,UTF-8跟GB2312也有问题。只得在Linux上安装GB2312(在Linux操作系统上又称zh_CN.GB2312)的字符集,具体请看下文。 Linux下几...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)