java - 正确处理 AppletViewer 的重新加载和重新启动

标签 java multithreading swing applet awt

当我的小程序第一次从干净的环境中启动时,一切都按照我期望的方式工作。我产生了两个线程,一个用于通用处理,一个用于图形处理。我从事件分派(dispatch)线程执行所有 GUI 操作调用。启动/停止从 appletviewer 正确处理,但重新启动/重新加载不是。我有一个名为 drawCanvas 的 Canvas 作为我的 Applet 内容 Pane 中的唯一组件,我使用双缓冲来绘制它。

我在这里观察到问题:

public void start() {   
    /* ... some stuff  */
    executeOnEDTAndWait( 
        new Thread() {
            @Override 
            public void run() {
                /* ... more stuff ... */
                setupDrawCanvas();

                if( drawCanvas.isDisplayable() ) {
                    drawCanvas.createBufferStrategy(2); 
                    /* ... some more stuff */
                } else {
                    /* This is where it runs into difficulties */
                }
    /* ... */

setupDrawCanvas 定义如下:

private void setupDrawCanvas() {
    setVisible(false);
    setIgnoreRepaint(true);

    getContentPane().removeAll();

    drawCanvas = new Canvas();

    drawCanvas.setName("drawCanvas");
    drawCanvas.setSize(
    newDrawCanvasDimension.width, 
    newDrawCanvasDimension.height);
    drawCanvas.setIgnoreRepaint(true);

    getContentPane().add(drawCanvas);

    getContentPane().setVisible(true);
    drawCanvas.setVisible(true);
    setVisible(true);
}

另外,这里是destroy()中的相关代码

public void destroy() {
    /* .. some stuff .. */

    /* dispose of drawCanvas */
    drawCanvas.setVisible(false);
    if( drawCanvas.getBufferStrategy() != null ) {
        drawCanvas.getBufferStrategy().dispose();
    }

    /* reset and disable the applet's GUI */
    setVisible(false);
    getContentPane().removeAll();
    removeAll();

    /* .. some more stuff */

第一次通过,一切正常。当我从 appletviewer 重新启动时,首先调用 stop() 导致我的所有线程进入等待状态。然后调用 destroy() 再次唤醒我的所有线程并让它们退出,以及在 EDT 上执行和 invokeAndWait() 来清理我的小部件并执行一个 setVisible(false)。所以在 destroy 完成后 appletviewer 再次调用 init/start 并且该过程完全像以前一样重复,除了它在我上面提到的区域的 start() 中失败。

我注意到对我来说意义不大的一件事是,如果我使用 appletviewer 克隆小程序,然后重新加载克隆,当我尝试重新启动或重新加载第一次克隆,但第二次会因异常而崩溃。

在尝试调试此问题时我注意到的另一件事是 appletviewer 和浏览器作为我的 applet 的宿主完全表现不同;他们甚至不会在相同条件下调用 init()start()。此外,重新启动和重新加载似乎只不过是调用 stop() -> destroy() -> init() -> start() 但对执行环境进行了细微的修改。

所以我的问题是,重新启动和重新加载操作的意义是什么(即它们何时使用),当它们发生时我的小程序在 appletviewer 中失败是否是一个问题?

最佳答案

好问题。 要回答这个问题,我们首先需要了解 java 代码块。 我们在将要执行的构造函数之前有一个匿名的静态 block 。

package com.test;

import java.applet.Applet;
import java.awt.*;

public class AppletTest extends Applet {
    {
        System.out.println("I m Anonymous block");
    }

    static {
        System.out.println("I m static block");
    }

    public AppletTest()
    {
        System.out.println("I m constructor");
    }

    public void init()
    {
        System.out.println("init");
    }

    public void start()
    {
        System.out.println("start");
    }

    public void stop()
    {
        System.out.println("stop");   
    }

    public void destroy()
    {
        System.out.println("destory");   
    }

    public void paint(Graphics g)
    {
        g.drawString("test Applet",10,10);
    }
}

调用:

 <applet code="AppletTest.class" height=300 width=300></applet>

当使用 appletviewer 运行此类时,您会注意到其中的区别。 小程序第一次运行你会得到

    I m static block
    I m Anonymous block
    I m constructor
    init
    start

在执行小程序重启时 -

stop
destory
init
start

和小程序重新加载

stop
destory
I m Anonymous block
I m constructor
init
start

对于你的第二个问题,小程序不保证在不同的操作系统、网络和硬件组件上输出相同。

关于java - 正确处理 AppletViewer 的重新加载和重新启动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7368188/

相关文章:

java - Playframework 推送到 Websocket

java - jFilechooser 显示文件夹

java - 调用start方法时,是否需要在java的run方法中同步方法?

Java 为什么我不能使用图形在面板上绘制

java - java - 如何在java 8流中进行条件操作以跳过下一个流操作?

java - 如何获取 FragmentPagerAdapter 中的当前位置?

java - 使用多线程或优先队列确定特定 API 调用优先级的方法?

javascript - 在哪个线程上处理和执行异步请求(如 AJAX 请求)

java - 获取分配给 JComponent 的名称

java - Swing 全尺寸 JPanel