`
kalogen
  • 浏览: 880007 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

serviceRepaints方法实现强制刷屏

    博客分类:
  • J2me
 
阅读更多

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 {
           
            int vmEvent;
           
            Display parentOfNextScreen;
           
            Displayable nextScreen;
           
            boolean callSeriallyPending;
           
            boolean invalidatePending;
           
            Item invalidItem;
           
            Item changedItem;
           
            int paintX1, paintY1, paintX2, paintY2;
           
            Object paintTarget;
           
            Object qLock;

           
            public EventQueue() {
                qLock = new Object();
                paintX1 = paintY1 = paintX2 = paintY2 = -1;
            }

           
            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 final Object LCDUILock = new Object();

       
        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.

分享到:
评论

相关推荐

    在移动设备上用J2ME实现动画.pdf

    - 通过`advance`方法实现动画帧的切换,每次调用此方法时切换到下一个图片,并触发画布的重新绘制。 - 如果使用了`clipList`,则根据不同的剪裁矩形绘制同一图片的不同部分,从而模拟出透明效果。 ```java public ...

    J2ME笔试 java

    `ServiceRepaints()`方法用于强制执行`repaint()`,确保更新立即生效,防止`repaint()`方法累积执行。 3. **J2ME音乐播放**: - 缺陷:不支持混音。解决方案:使用厂商特定的API来实现混音功能。游戏中的音乐切换...

    游戏框架.pdf

    `Run()`方法持续调用`repaint()`、`serviceRepaints()`和`mainLogic()`,保持游戏画面的更新和逻辑处理。 在游戏框架中,`ANT`工具是Java项目构建的重要工具,它使用XML文件描述构建过程。每个构建文件由一个`...

    j2me代码--合金带头框架代码

    游戏的核心循环主要通过`refresh()`方法实现,它调用`repaint()`和`serviceRepaints()`刷新屏幕。`stayapp()`和`exitapp()`控制游戏是否继续运行。`toScreenx()`和`toScreeny()`是坐标转换函数,将世界坐标转换为...

    j2me中文api(简陋版),自己翻译的,目前只翻译了常用的方法

    13. `serviceRepaints()`:处理优先级较高的绘图请求。 14. `setFullScreenMode(boolean mode)`:切换Canvas到全屏或正常模式。 Displayable是J2ME中表示可显示内容的接口,它可以是窗口、对话框或其他可视元素。...

    J2ME游戏的基本结构

    此外,`serviceRepaints()`方法用来处理系统的重绘请求,确保画布及时更新。 总结起来,J2ME游戏的基本结构是一个持续运行的游戏循环,通过处理输入、执行逻辑和更新画面来实现游戏的交互和动态效果。这种结构虽然...

    J2ME中文API帮助文档

    12. `serviceRepaints()`:处理待处理的画布更新请求。 13. `setFullScreenMode(mode)`:切换Canvas到全屏或非全屏模式。 14. `showNotify()`:当Canvas即将在屏幕上显示时调用。 接下来是Displayable类,它是J2ME...

    自编写解霸源代码 供大家共享,本程序是J2ME编写

    自编写解霸源代码 import javax.microedition.lcdui.Canvas; class Game extends Thread { public static int speed = 50; public static int count = 0;... msf.mc.serviceRepaints(); } while(true); } }

Global site tag (gtag.js) - Google Analytics