简体   繁体   English

在上一个方法完成之前调用的方法

[英]Method Called Before Previous Method Finishes

I'm working on a simple translation app as part of a university project. 作为大学项目的一部分,我正在开发一个简单的翻译应用程序。 For the translation process, I query MyMemory's Translate API using Retrofit and I retrieve the translated output as a String. 对于翻译过程,我使用Retrofit查询MyMemory的Translate API ,并将翻译后的输出作为String检索。 This is working fine for the most part, but it's causing some issues in other areas of my program. 这在大多数情况下都可以正常工作,但在程序的其他方面却引起了一些问题。

When I make a call to retrieve a translation from the library, subsequent methods begin to run before the translation is fully recieved - this then prevents those methods from working fully since they rely on the received translation. 当我打电话从库中检索翻译时,随后的方法在完全接收到翻译之前就开始运行-这会阻止这些方法完全起作用,因为它们依赖于所接收的翻译。

Here are some relevant snippets of my code that might explain the question better: 以下是我的代码的一些相关摘要,可能会更好地解释该问题:

TranslateAPI: (Interface that i use to retrieve a translation) TranslateAPI :(我用来检索翻译的接口)

public class TranslateAPI {
private static final String ENDPOINT = "http://api.mymemory.translated.net";
public final static String FRENCH = "FR";
public final static String ENGLISH = "EN";
public final static String ITALIAN = "IT";
public final static String GREEK = "EL";
public final static String SPANISH = "ES";
private final TranslateService mService;
String translation = "";

public interface TranslateService {
    @GET("/get")
    Call<TranslatedData> getTranslation(
            @Query("q") String textToTranslate,
            @Query(value = "langpair", encoded = true)
            String languagePair);
}

public TranslateAPI() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(ENDPOINT)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    mService = retrofit.create(TranslateService.class);
}

public String translate(final String textToTranslate, final String fromLanguage, final String toLanguage) {
    mService.getTranslation(textToTranslate, URLEncoder.encode(fromLanguage + "|" + toLanguage))
            .enqueue(new Callback<TranslatedData>() {

                @Override
                public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
                    String output =
                            String.format(response.body().responseData.translatedText);
                    String.format("Translation of: %s, %s->%s = %s", textToTranslate,
                            fromLanguage, toLanguage, response.body().responseData.translatedText);
                    System.out.println("Result: " + output);
                    translation = output;
                    System.out.println("The result of the field translation is: " + translation);
                }

                @Override
                public void onFailure(Throwable t) {
                    System.out.println("[DEBUG]" + " RestApi onFailure - " + "");
                }
            });
    return translation;
}

} }

In the code above, the translate(final String textToTranslate, final String fromLanguage, final String toLanguage ) method successfully returns the translated output as a string. 在上面的代码中, translate(final String textToTranslate,final String fromLanguage,final String toLanguage )方法成功地将转换后的输出作为字符串返回。

Now, to demonstrate exactly what goes wrong, assume the following code snippet for my main activity: 现在,为了确切说明出了什么问题,请针对我的主要活动假设以下代码片段:

private void runChatBot() {
    translateOutput(input, targetLanguage); //calls the translate method of the TranslateAPI class
    System.out.println("translatedOutput value in MainActivity: " + translatedOutput);
    //Use translated output here

}

What happens here is that the print statement in runChatbot() executes before the call to the translation API. 此处发生的是runChatbot()中的print语句在调用翻译API之前执行。 This is not the desired behaviour, as I would like the translateOutput() method to execute fully before any following instructions. 这不是期望的行为,因为我希望translateOutput()方法在以下任何指令之前完全执行。

Any help is much appreciated. 任何帮助深表感谢。 Thanks in advance :) 提前致谢 :)

UPDATE: Current code after initial answers 更新:初始答案后的当前代码

TranslateAPI - Declarations TranslateAPI-声明

public interface Callbacks {
    void onTranslationReceived(String result);
    void onTranslationFailed();
}

TranslateAPI - translate() TranslateAPI-translate()

    public void translate(final String textToTranslate, final String fromLanguage, final String toLanguage) {
    mService.getTranslation(textToTranslate, URLEncoder.encode(fromLanguage + "|" + toLanguage))
            .enqueue(new Callback<TranslatedData>() {

                @Override
                public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
                    String output =
                            String.format(response.body().responseData.translatedText);
                    String.format("Translation of: %s, %s->%s = %s", textToTranslate,
                            fromLanguage, toLanguage, response.body().responseData.translatedText);
                    System.out.println("Result: " + output);
                    translation = output;
                    System.out.println("The result of the field translation is: " + translation);
                }

                @Override
                public void onFailure(Throwable t) {
                    System.out.println("[DEBUG]" + " RestApi onFailure - " + "");
                }
            });
}

MainActivity: 主要活动:

    @Override
public void onTranslationReceived(String result) {
    runChatBot();
}

@Override
public void onTranslationFailed() {
    //Handle failure here
}

public void runChatBot() {
    translatedOutput = translateAPI.getTranslation();
    System.out.println("translatedOutput value in MainActivity: " + translatedOutput);
    userOutputView.setText(translatedOutput);
    ttsResponse(translatedOutput, TTSLanguage);
    setVisualCue(chatBot.getVisualMatch());
    chatBot.clearResults();
}

Since your translate() method is asynchronous, you should define a callback in TranslateAPI to send the result back to your Activity when the result is received. 由于您的translate()方法是异步的,因此您应该在TranslateAPI定义一个回调,以便在收到结果后将结果发送回Activity。 By doing this, you would then only perform work on the translation result once you know you've received a response from TranslateAPI . 这样,仅当您知道收到TranslateAPI的响应后,才可以对翻译结果进行处理。

So in TranslateAPI you would define a callback interface: 因此,在TranslateAPI您将定义一个回调接口:

public interface Callbacks {
    void onTranslationReceived(String result);
}

Then you would have your Activity implement TranslateAPI.Callbacks and implement the callback like this: 然后,您将使Activity实现TranslateAPI.Callbacks并实现如下所示的回调:

public void onTranslationReceived(String result) {
    //do something with the result
    runChatBot(result); //or something similar
}

Then, once you receive the response in the callback, you do whatever it is you have to do with the translation result. 然后,一旦您在回调中收到响应,就可以执行翻译结果。 This way, you know you will never be executing anything on the translated result until the translation is complete. 这样,您知道在转换完成之前,您永远不会对转换结果执行任何操作。

EDIT IN RESPONSE TO COMMENTS 编辑以回应评论


So in order to actually send the response to your Activity once the translate response is received, you need to pass a reference to your Activity into TranslateAPI . 因此,为了在收到翻译响应后将响应实际发送到您的Activity,您需要将对您Activity的引用传递给TranslateAPI Since your Activity implements the callbacks, you can simply pass this in: TranslateAPI translateApi = new TranslateAPI(this); 由于您的活动implements的回调,你可以简单地传递this :在TranslateAPI translateApi = new TranslateAPI(this);

Then in your TranslateAPI , you'll need to take this reference and use it as the "listener" of your callbacks. 然后,在您的TranslateAPI ,您需要获取此引用并将其用作回调的“侦听器”。 So in TranslateAPI you'll want to define a variable like this private Callbacks listener; 因此,在TranslateAPI您将需要定义一个类似于此private Callbacks listener;的变量private Callbacks listener; and you'll assign this in your TranslateAPI constructor the value that's passed in from the Activity. 然后您将在TranslateAPI构造函数中为其分配从Activity传入的值。 So your TranslateAPI constructor might look like this: 因此,您的TranslateAPI构造函数可能如下所示:

public TranslateAPI(Callbacks listener) {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(ENDPOINT)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    mService = retrofit.create(TranslateService.class);

    //this is the line you would add...
    this.listener = listener;
}

And then in your onResponse() callback in TranslateAPI , you simply pass the value to the listener, which passes it back to the implemented method in your Activity. 然后,在TranslateAPI onResponse()回调中,您只需将值传递给侦听器,该侦听器会将其传递回Activity中的已实现方法。 Like this: 像这样:

@Override
public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
    String output = String.format(response.body().responseData.translatedText);
    String.format("Translation of: %s, %s->%s = %s", textToTranslate, fromLanguage, toLanguage, response.body().responseData.translatedText);
    System.out.println("Result: " + output);
    translation = output;
    System.out.println("The result of the field translation is: " + translation);

    //this is the line you would add...
    listener.onTranslateReceived(translation);
}

Hope this helps clarify things. 希望这有助于澄清问题。 Let me know if you have any more questions! 让我知道您是否还有其他问题!

this happens because code is executed asynchronous. 发生这种情况是因为代码是异步执行的。 Your retrofit network request takes some time to complete, so by default, java will execute the next line of code before it concludes. 改造网络请求需要一些时间才能完成,因此默认情况下,java将在结束之前执行下一行代码。 To solve this you must use the retrofit callback onResponse and onFailure. 为了解决这个问题,您必须使用改造回调onResponse和onFailure。

I sugest you to create a new interface and pass it on constructor os method of your TranslateApiCode. 我建议您创建一个新接口,并将其传递给TranslateApiCode的构造方法os方法。 Something like: 就像是:

public interface OnTranslate {
  void onSuccess(); // here you can pass any object you need later
  void onError(); // here you can pass any object you need later
}



public String translate(final String textToTranslate, final String fromLanguage, final String toLanguage) {
mService.getTranslation(textToTranslate, URLEncoder.encode(fromLanguage + "|" + toLanguage))
        .enqueue(new Callback<TranslatedData>() {

            @Override
            public void onResponse(Response<TranslatedData> response, Retrofit retrofit) {
                String output =
                        String.format(response.body().responseData.translatedText);
                String.format("Translation of: %s, %s->%s = %s", textToTranslate,
                        fromLanguage, toLanguage, response.body().responseData.translatedText);
                System.out.println("Result: " + output);
                translation = output;
                System.out.println("The result of the field translation is: " + translation);

                myOnTranslateVariable.onSuccess(); 


            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("[DEBUG]" + " RestApi onFailure - " + "");
                myOnTranslateVariable.onError();
            }
        });
return translation;
}


private void runChatBot() {
  translateOutput(input, targetLanguage, new OnTranslate() {
    void onSucess() {
      System.out.println("translatedOutput value in MainActivity: " +     translatedOutput);
    }
    void onError() {
      System.out.println("some error happened");
    }


  }); //calls the translate method of the TranslateAPI class

 //Use translated output here

}

Try Using Handler to notify when translation is completed and then perform the required operations. 尝试使用Handler通知翻译何时完成,然后执行所需的操作。 Thanks 谢谢

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

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