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.

使用 Jni 调用 Dll 的实现JAVA在cmd控制台刷屏

第一步:编写Java端代码 定义一个Java类Cls package pacmanDemo; /** * Created by DH on 2015-10-24. */ public class...
  • dhown
  • dhown
  • 2015年10月24日 21:21
  • 511

VC无闪烁刷屏技术的实现---VC中用GDI函数实规高速平滑动画

摘要:许多游戏软件的开发中,实现高速平滑的动画需要许多比较深的技术,如:OpenGL、DirectX,并且可能还要开发人员有深厚的数学功底。但是,我们在开发一些小游戏,或为应用程序的界面实现一些动画效...

VC无闪烁刷屏技术的实现

在实现绘图的过程中,显示的图形总是会闪烁,笔者曾经被这个问题折磨了好久,通过向高手请教,搜索资料,问题基本解决,现将文档整理出来以供大家参考. 1.显示的图形为什么会闪烁   我们的绘图过程大...

VC无闪烁刷屏技术的实现

在实现绘图的过程中,显示的图形总是会闪烁,笔者曾经被这个问题折磨了好久,通过向高手请教,搜索资料,问题基本解决,现将文档整理出来以供大家参考. 1.显示的图形为什么会闪烁   我们的绘图过程大...

Ajax不刷屏实现刷新.txt

  • 2009年10月12日 20:50
  • 2KB
  • 下载

今天被TensorFlowLite刷屏了吧,偏要再发一遍

翻译 | 刘畅Troy 谷歌今天终于发布了TensorFlow Lite 的开发者预览!该项目是在5月份的I/O开发者大会上宣布的,据Google网站描述,对移动和嵌入式设备来说,T...

“我祝你不幸并痛苦”,首席大法官说了番狠话却被追捧刷屏

罗伯茨,2005年9月由小布什总统提名,参议院批准通过,就任美国联邦最高法院的第17任首席大法官,是美国两个世纪以来最年轻的首席大法官。 “人们唯有遭遇不公时,才知道公正的价值”,约翰·罗伯茨大...

LD编辑距离算法-->可用于聊天系统的刷屏控制

/* 1 Set n to be the length of s. Set m to be the length of t. If n = 0, return m and exit. If ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:serviceRepaints是如何实现强制刷屏的!
举报原因:
原因补充:

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