简体   繁体   English

Java LibGDX SwingWorker冻结GUI(块上传器)

[英]Java LibGDX SwingWorker Freezes GUI (Chunk Uploader)

I am currently working on a chunk uploader (in Java) to upload files to a private server. 我目前正在使用块上载器(在Java中)将文件上载到私有服务器。 Everything works perfectly, but while the application is uploading the file, it freezes the window. 一切正常,但在应用程序上载文件时,它冻结了窗口。 After the upload everythin returns to normal, but not during. 上载后,一切都恢复正常,但在恢复过程中没有恢复。 I know it uploads because it works and it displays the progress in the Console. 我知道它可以上传,因为它可以正常工作并且可以在控制台中显示进度。 So, I tried to move all the calculations on a different thread. 因此,我尝试将所有计算移到不同的线程上。 It still ran properly, but froze. 它仍然可以正常运行,但是冻结了。 Furthermore I read about SwingWorker, and I gave that a go, but it is still freezing the main GUI. 此外,我读到了有关SwingWorker的文章,我尝试了一下,但是它仍然冻结了主GUI。

Here is the class for SwingWorker (All methods are in order so you shouldn't get lost, and each contains a comment explaining purpose) (It is a lot of code, but you should really only need to look through the BeginUpload() method, as that is where the loop is located) 这是SwingWorker的类(所有方法都井井有条,因此您不会迷路,每个方法都包含一个解释目的的注释)(很多代码,但是您实际上只需要查看BeginUpload()方法) ,因为这是循环所在的位置)

public class ChunkUploader extends SwingWorker<String, Object> {
    public String Text="";
    public String Text2="";

    boolean Uploading=false;
    private String Actual="";
    private int CurrentChunk=0;

    private int BytePosition=0;

    private int ChunkSize=100000;
    private String Contents="";
    private String FileName;
    private int PackageNumber;
    private String ByteString;
    private boolean Finalize;
    private String Password;
    private int TotalChunks;
    private byte[] bytes;
    TextPrompt Prompt;

    public double Progress=0;

    public boolean done=false;
    public ChunkUploader(String FileName) {
    //Prepares the thing
        this.FileName=FileName;
        Prompt = new TextPrompt();
    }

    @Override
    protected String doInBackground() throws Exception {
    //Calls the first method
            PrepareUpload(FileName);
        return null;
    }

    private void PrepareUpload(String FileName) {
    //Loads the file and then prompts for a password;
        if(Gdx.files.absolute(FileName).exists()) {
            Actual=FileName;
            System.out.println(FileName);///C:/T/Image.png
            Uploading=true;
            String pp[]=FileName.split("/");
            this.FileName=pp[pp.length-1];
            System.out.println(this.FileName);///C:/T/Forgive.txt
            FileHandle h=Gdx.files.absolute(Actual);
            Text = "Loading file..."+Actual;
            bytes = h.readBytes();
            Text2="";
            Prompt.Prepare("Password", this);
            Gdx.input.getTextInput(Prompt, "Input Dynamic Password:", "");
        }
    }

    public void PromptReturn(String Return, String Text) {
    //Reads the user input into the variable Password. Starts the upload
        if(Return.equals("Password")) {
            Password=Text;
            BeginUpload();
        }
    }

    private void BeginUpload() {
    //Splits the data to chunks and encodes it Base64. Sends the data to Return();

        Text = "Total size: "+Integer.toString(Contents.length());
        TotalChunks=(int) Math.ceil(bytes.length/ChunkSize);
        TotalChunks++;
        String CurrentSend="";
        CurrentChunk=0;

        String All="";

        Text2="Starting Upload...";

        for(int i=0; i<TotalChunks; i++) {
                byte[] temp=GetByteRange(CurrentChunk*ChunkSize, GetWidth(CurrentChunk*ChunkSize, bytes.length, ChunkSize));
                System.out.print(Double.toString(100*BytePosition/bytes.length)+"% complete.");
                Text = Double.toString(100*BytePosition/bytes.length)+"% complete.";
                BytePosition=GetWidth(CurrentChunk*ChunkSize, bytes.length, ChunkSize);

                CurrentSend=Base64.getEncoder().encodeToString(temp);CurrentChunk, false, Password, TotalChunks, FileName);
                String p="";
                while(p.isEmpty()) {
                    try {
                        p=Return(CurrentSend, CurrentChunk, false);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                All = All+CurrentSend;
                CurrentChunk=CurrentChunk+1;
        }
        Text2="Finalizing...";
        String p="";
        while(p.isEmpty()) {
            try {
                p=Return(CurrentSend, TotalChunks, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Text2="Upload should be complete.";
    }

    public byte[] GetByteRange(int Start, int End) {
        byte[] temp = new byte[End-Start];

        for(int i=Start; i<End; i++) {
            temp[i-Start] = bytes[i];
        }

        return temp;
    }

    public int GetWidth(int Position, int Size, int ChunkSize) {
        if(Position+ChunkSize<=Size) {
            int p=ChunkSize+Position;
            return p;
        }
        else {
            return Size;
        }
    }

    public String Return(String ByteString, int PackageNumber, boolean finalize) throws Exception {
    //Sends the file data to the server.
        String url = "http://www.stackoverflow.com/";
        URL obj = new URL(url);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();

        con.setRequestMethod("POST");
        con.setRequestProperty("User-Agent", "Mozilla/5.0");
        con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");

        String urlParameters = "Pass="+Password+"&FileName="+FileName+"&PackageNumber="+Integer.toString(PackageNumber)+"&FinalPackageNum="+TotalChunks+"&Bytes="+ByteString;
        if(finalize==true) {
            urlParameters=urlParameters+"&State=Final&FinalPackageNum="+Integer.toString(TotalChunks);
        }
        con.setDoOutput(true);
        DataOutputStream wr = new DataOutputStream(con.getOutputStream());
        wr.write(urlParameters.getBytes(StandardCharsets.UTF_8));
        wr.flush();
        wr.close();

        BufferedReader in = new BufferedReader(
                new InputStreamReader(con.getInputStream()));
        String inputLine;
        StringBuffer response = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();
        con.disconnect();
        System.out.println(response.toString());
        System.out.println("___________________");
        return response.toString();
    }
}

Here is the LibGDX Screen that the ChunkUploader class is created on. 这是创建ChunkUploader类的LibGDX屏幕。

public class FileUploadScreen implements Screen {
    String FilePath;
    String Text="";
    String Text2="";

    ChunkUploader Uploader;
    OrthographicCamera camera;

    MyGame game;
    public FileUploadScreen(String FilePath, MyGame game) {
        this.game=game;
        camera = new OrthographicCamera();
        camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        this.FilePath = FilePath;
        Uploader = new ChunkUploader(FilePath);
        Uploader.execute();
    }
    @Override
    public void render(float delta) {
        Text=Float.toString(delta);
        game.MainFont.setColor(Color.WHITE);
        game.Screen.set(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        camera.update();
        game.batch.setProjectionMatrix(camera.combined);

        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        game.batch.begin();
            game.MainFont.draw(game.batch, Text, 100, game.Screen.y-50);
            game.MainFont.draw(game.batch, Text2, 100, game.Screen.y-100);
        game.batch.end();
    }
}

And for good measure, here is the text prompt: 出于很好的考虑,这是文本提示:

public class TextPrompt implements TextInputListener {
            private String Text="";
            public boolean Active;
            private String Return;
            private ChunkUploader parent;

            public TextPrompt() {
                Active = false;
            }
            public void Prepare(String Return, ChunkUploader Parent) {
                Active = true;
                this.Return=Return;
                this.parent=Parent;
            }
            @Override
            public void input(String text) {
                Text = text;
                Active = false;
                parent.PromptReturn(Return, Text);
            }
            @Override
            public void canceled() {
                Text = "";
                Active = false;
            }
            public String GetInput() {
                return Text;
            }
}

Again, as long as the file is not uploading everything runs fine. 同样,只要文件未上传,一切都将正常运行。 I'm just confused, because if it is uploading on a separate thread then it should not be conflicting with the GUI. 我只是感到困惑,因为如果它是在一个单独的线程上载,则它不应与GUI冲突。 Can anybody inform me as to what I am doing wrong? 有人可以告诉我我做错了什么吗?

Alright, so it looks like there are a few problems with this. 好吧,看来这有一些问题。 First of all, all methods in the ChunkUploader class need to be called by doInBackground(). 首先,ChunkUploader类中的所有方法都需要由doInBackground()调用。 When you look inside the PromptReturn method, BeginUpload(); 当您查看PromptReturn方法内部时,BeginUpload(); is called. 叫做。

To fix this, we need to get a little creative. 要解决此问题,我们需要有一点创意。 Here are the changes that should be made: 以下是应进行的更改:

A boolean variable needs to be created that is accessible by both doInBackground() and PromptReturn(). 需要创建一个布尔变量,可以通过doInBackground()和PromptReturn()进行访问。 Its initial value should be false. 其初始值应为false。

Next, make this change to the first few methods: 接下来,对前几个方法进行更改:

private boolean Begin = false;

public void PromptReturn(String Return, String Text) {
//Reads the user input into the variable Password. Starts the upload
    if(Return.equals("Password")) {
        Password=Text;
        //BeginUpload();
        Begin = true;
    }
}

@Override
protected String doInBackground() throws Exception {
    //Calls the first method, and waits to call the second.
    PrepareUpload(FileName);
    boolean run=true;
    while(run) {
        if(Begin) {
            BeginUpload()
            run=false;
        }
    }
    return null;
}

Furthermore it is worthwhile to note that the Base64 encoder you are using only works with desktop applications. 此外,值得注意的是,您使用的Base64编码器仅适用于桌面应用程序。 You should consider switching to this Base64 encoder/decoder. 您应该考虑切换到此Base64编码器/解码器。 It fulfills all of your current needs with the way you are using it, and is super easy to implement. 它通过使用方式来满足您当前的所有需求,并且易于实现。 Just copy the Base64.java into your project and you can now use it for desktop and android. 只需将Base64.java复制到您的项目中,您现在就可以将其用于桌面和android了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM