Avoiding Flicker

When the contents of a screen seem to blink or seem unsteady, the screen is said to flicker. Flicker is annoying to users and can actually be harmful to persons with photosensitive epilepsy if the flicker occurs at a rate of 2 to 55 flashes per second. This section offers some guidelines for avoiding flicker.

app Developers

Recommend: Java graphics bulb2_icon.gif When you create an app that draws to the screen, minimize flicker by organizing your data to support redrawing as little of the screen as possible.

For example, SmartTicket draws a seating chart onto a canvas so that users can choose seats in a theater. Users can navigate through the empty seats, select seats, and change their selections. There are many ways to represent the data that makes this possible. (The data includes the number of rows in the theater, the number of seats per row, the status of each seat, and so on.) The following paragraphs describe two ways to organize this data; they require a very different amount of redrawing. One way to represent the data on the Canvas screen is with an array. Each row of the array would correspond to a row in the theater. Cells could correspond to seats (such as current, occupied, unoccupied) and nonseat spaces (such as aisles). Each time the user moves from one empty seat to another, the app would have to find the cell for the user's current seat, update its status, find the cell representing the next unoccupied seat in the direction in which the user navigated, update its status, use the array data to recompute the color of each pixel on the canvas, and redraw the entire canvas. Having to do this much work could cause flicker. Another way to represent the data for the canvas screen is to have, in addition to the array, fields for the old and new seat locations. Using this data organization, the app could do much less work. Each time the user moves from one empty seat to another, it would retrieve the user's current location (instead of searching for it), update the status of that cell, find the next unoccupied seat in the direction in which the user navigated, update that cell's status, recompute the colors of the pixels that correspond to the old and new seats (instead of the whole screen), and request repaints of the areas containing the updated pixels (instead of the whole screen). This data organization means less computation and repainting and helps to minimize flicker.

Double-Buffering

Double-buffering is another way to minimize flickering of the screen. A device that provides double-buffering draws your requested updates onto an image that is not the screen. This image is called a buffer, or backing store. The device updates the screen by transferring (painting) the buffer onto the screen. The device can transfer the image quickly, minimizing flickering and delays in screen updates.

app Developers

Recommend: Java graphics bulb2_icon.gif Create apps that use double-buffering. Simulate it with an app buffer or use a game canvas if it is not available on a Canvas screen. To simulate double-buffering, create a buffer (an image) within the app, draw to it, then paint the screen from the buffer.

Consider: Try to both use double-buffering and minimize the area that you need to redraw. If you use double-buffering but do not try to minimize the size of the update area, you could end up recalculating and redrawing the entire buffer before transferring it onto the screen. The delay caused by the calculations could cause flicker or make the device seem unresponsive. Similarly, if you minimize the update area but do not use double-buffering, you might still get some flicker.

MIDP Implementors

Recommend: Java graphics bulb2_icon.gif Provide double-buffering whenever possible, and publish the feature for app developers. Include a list of exceptions, such as the amount of available memory.

Batch Paint Requests

In addition to the techniques used by app developers, MIDP implementors can also help to minimize flickering and resource usage.

MIDP Implementors

Recommend: Java graphics bulb2_icon.gif Process paint requests in batches to minimize resource usage. Batching paint requests merges the parts of the screen that each paint request would have affected (called clipping regions) into a single clipping region. The batched request affects all parts of the screen that the individual paint requests would have affected.

For example, as the user navigates through the SmartTicket canvas, the app could make two repaint requests for each move: one would request that the old seat be repainted and the other would request that the new seat be repainted. If the MIDP implementation did not batch paint requests, redrawing the old and new seats would result in two separate screen paintings. Batching the requests would have the screen redraw the rectangle created by the old and new seat locations, possibly saving resources. Screenshot shows an old seat location, a new seat location, and the rectangle that results from combining their clipping regions.

Screenshot Rectangle Redrawn between Two Selectable Seats

Java graphics 10fig14.gif


app Developers

Consider: When you write the code for your canvas's paint methods, check the clipping region in case the MIDP implementation has batched paint requests. You cannot assume a one-to-one correspondence between your calls to the repaint methods and the system's calls to the canvas's paint method. If the MIDP implementation batches repaint requests, the paint method could be asked to paint a seemingly arbitrary portion of the screen.

If you do not check the clipping region, you could try to repaint too much of the screen or miss repainting part of the screen. If you try to repaint too much of the screen (that is, if you don't check the clipping region, but instead have the repaint method try to redraw the entire screen each time), you would waste resources. If you miss repainting parts of the screen, the app will not respond properly to the user's key presses or screen taps, making the app unusable. For example, assume that you wrote the paint method for the example shown in Screenshot as though it would only ever be asked to repaint a single seat. (That is, assume that you wrote the paint method as though there would be a one-to-one correspondence between the app's requests to repaint the screen and calls to the paint method.) If the MIDP implementation batched the paint requests, as shown in Screenshot, your app might clear the old seat location but not draw the new location. The MIDlet would not respond properly to the user's key presses or touches.



   
Comments