API.AI: как остановить AsyncTask по нажатию кнопки AIButton?

Я использую AIButton в своем приложении, и у меня есть AsyncTask, который выполняется после нажатия кнопки AIButton и получения некоторой команды, а выполнение AsyncTask иногда занимает слишком много времени.

Вот мой код:

final AIConfiguration config = new AIConfiguration("xxx",
                AIConfiguration.SupportedLanguages.English,
                AIConfiguration.RecognitionEngine.System);

listenButton = (AIButton) findViewById(R.id.micButton);

config.setRecognizerStartSound(getResources().openRawResourceFd(R.raw.test_start));
config.setRecognizerStopSound(getResources().openRawResourceFd(R.raw.test_stop));
config.setRecognizerCancelSound(getResources().openRawResourceFd(R.raw.test_cancel));

listenButton.initialize(config);
listenButton.setResultsListener(this);

Вот AsnycTask:

class translate extends AsyncTask<String, Void, String> {

    String translatedText = "";

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        loading.setMessage("Loading");
        loading.show();
    }

    @Override
    protected String doInBackground(String... params) {

        String text = params[0];
        String toBeConvertedIn = params[1];

        Log.d("TEXT", text);
        Log.d("TBCI", toBeConvertedIn);

        try {
            String encodedText = URLEncoder.encode(text, "UTF-8");
            HttpHandler httpHandler = new HttpHandler();
            String url = "https://translate.yandex.net/api/v1.5/tr.json/translate?key=xxxxxxx&text=" + encodedText + "&lang=" + toBeConvertedIn;
            String jsonStr = httpHandler.makeServiceCall(url);

            if (jsonStr != null) {
                Log.e(TAG, "Response from url: " + jsonStr);
                try {
                    JSONObject jsonObj = new JSONObject(jsonStr);
                    Log.d("jsonObj", String.valueOf(jsonObj));

                    JSONArray translatedTextObj = jsonObj.getJSONArray("text");

                    for (int i=0; i<translatedTextObj.length(); i++) {
                        translatedText = translatedTextObj.getString(i);
                        Log.d("translatedText", translatedText);
                    }

                } catch (JSONException e) {
                    Log.d(TAG, e.getMessage());
                }
            } else {
                Log.e(TAG, "Couldn't get json from server.");
            }

        } catch (UnsupportedEncodingException e) {
            Log.d(TAG, e.getMessage());
        }

        return translatedText;
    }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            hTV.setText(s);
            if (loading.isShowing()) {
                loading.dismiss();
            }
        }
    }

Я вызываю указанный выше метод AsyncTask в onResult() следующим образом:

public void onResult(final AIResponse response) {

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "onResult");

            Log.i(TAG, "Received success response");

            // this is example how to get different parts of result object
            final Status status = response.getStatus();
            Log.i(TAG, "Status code: " + status.getCode());
            Log.i(TAG, "Status type: " + status.getErrorType());

            final Result result = response.getResult();
            Log.i(TAG, "Resolved query: " + result.getResolvedQuery());

            Log.i(TAG, "Action: " + result.getAction());
            final String speech = result.getFulfillment().getSpeech();

            final Metadata metadata = result.getMetadata();
            if (metadata != null) {
                Log.i(TAG, "Intent id: " + metadata.getIntentId());
                Log.i(TAG, "Intent name: " + metadata.getIntentName());
            }

            final HashMap<String, JsonElement> params = result.getParameters();
            if (params != null && !params.isEmpty()) {
                Log.i(TAG, "Parameters: ");
                for (final Map.Entry<String, JsonElement> entry : params.entrySet()) {

                    switch (response.getResult().getMetadata().getIntentName()) {
                        case "Translate":
                            if (entry.getValue() != null) {
                                if (entry.getKey().equals("translate")) {

                                    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MainActivity.this);
                                    LayoutInflater inflater = MainActivity.this.getLayoutInflater();
                                    final View dialogView = inflater.inflate(R.layout.translate_alertdialog, null);
                                    dialogBuilder.setView(dialogView);

                                    final EditText textToTranslate = (EditText) dialogView.findViewById(R.id.text_to_translate);
                                    final AutoCompleteTextView chooseLanguage = (AutoCompleteTextView) dialogView.findViewById(R.id.choose_language);
                                    ArrayAdapter adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_spinner_item, languages);
                                    chooseLanguage.setAdapter(adapter);

                                    dialogBuilder.setTitle("What should I translate?");
                                    dialogBuilder.setPositiveButton("Translate", new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int whichButton) {
                                            if (!textToTranslate.getText().toString().isEmpty()) {
                                                if (!chooseLanguage.getText().toString().isEmpty()) {

                                                    switch (chooseLanguage.getText().toString().toLowerCase()) {
                                                        case "french":
                                                            new translate().execute(textToTranslate.getText().toString(), "az");
                                                            break;
                                                    }
                                                }
                                            }
                                        }
                                    });
                                    dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int whichButton) {
                                            //pass

                                        }
                                    });
                                    AlertDialog b = dialogBuilder.create();
                                    b.show();
                                } else {
                                    Log.d("null", "No translate parameter");
                                }
                            } else {
                                Log.d("null", "No translate entry value");
                            }
                            break;
                    }
                }
            }
        }

    });

}

Итак, я хочу остановить все запущенные AsyncTask при нажатии кнопки AIButton, чтобы предыдущие задачи были остановлены для выполнения новой задачи. Как это сделать?

Проблема здесь в том, что вы не можете сделать что-то вроде: listenButton.onClickListener() здесь.


person Hammad Nasir    schedule 08.09.2017    source источник
comment
@YvetteColomb Я нигде не создаю экземпляр, а называю его как new translate().execute(param1, param2); везде, где мне это нужно.   -  person Hammad Nasir    schedule 10.09.2017
comment
Добавьте новый конструктор в класс translate, передающий объект, то есть логический, и сохраните экземпляр этого объекта при нажатии кнопки. Вы проверяете значение объекта Boolean в doInBackground, чтобы увидеть, изменится ли значение на false для выхода. Когда вы нажимаете кнопку, вы меняете значение объекта Boolean на false.   -  person anemomylos    schedule 10.09.2017
comment
@EasyJoin.net проблема в том, что в этом случае невозможно отследить нажатие кнопки. Прочитайте вопрос еще раз.   -  person Hammad Nasir    schedule 11.09.2017
comment
@HammadNasir, вы создаете экземпляры класса translate в других местах, кроме метода onResult, и, в частности, в case "french":?   -  person anemomylos    schedule 11.09.2017
comment
@EasyJoin.net, но вы написали. Когда вы нажимаете кнопку, вы меняете значение логического объекта на false. Как я должен изменить значение здесь, если нет onclick?   -  person Hammad Nasir    schedule 11.09.2017
comment
@HammadNasir, вы уже определили метод onClick, в котором вы создаете экземпляр translate. Я пропустил часть вашего кода?   -  person anemomylos    schedule 11.09.2017
comment
@EasyJoin.net onClick должен быть установлен на listenButton, верно? Весь код, относящийся к listenButton, написан в вопросе.   -  person Hammad Nasir    schedule 11.09.2017
comment
пожалуйста, приложите некоторые усилия, чтобы сделать ваш код менее вложенным. Это не только очень сложно прочитать, но и невозможно проверить   -  person Tim    schedule 11.09.2017


Ответы (4)


Используйте логическое значение отмены (логическое значение mayInterruptIfRunning).

Сделайте asyncTask переменной класса.

AsyncTask translate_ = new translate();

Тогда назовите это так на месте.

translate_.execute(textToTranslate.getText().toString(), "az");

Внутри кнопки onclick отмените asyncTask.

translate_.cancel(true);

Затем проверьте в своем цикле, что задача была отменена, и установите перерыв.

for (int i=0; i<translatedTextObj.length(); i++) {
    translatedText = translatedTextObj.getString(i);
    Log.d("translatedText", translatedText);
    if(isCancelled())
        break;
}

Эти вопросы также дают больше разнообразия в том, как это сделать:

Android — принудительно отменить AsyncTask

Как остановить поток асинхронной задачи в Android?

Было бы разумно также управлять задачей на обратном прессе. Возможно отменить задачу в активности на паузе.

public void listenButtonOnClick(final View view) {
    // aiService.startListening();
    // add more details in here

    if (aiService != null) {
        switch (currentState) {
            case normal:
                aiService.startListening();
                break;
            case busy:
                aiService.cancel();
                translate_.cancel(true);
                break;
            default:
                aiService.stopListening();
                translate_.cancel(true);
                break;
}

Или отмените задачу, когда aiservice отменяется или останавливается.

@Override
public void onListeningStarted() {}

@Override
public void onListeningCanceled() {
    translate_.cancel(true);
}

@Override
public void onListeningFinished() {
    translate_.cancel(true);
}

Есть и другие способы управления этим, изучите свои варианты. Внимательно изучите это и вопросы SO, указанные выше.

Если вы посмотрите документы.

apiai-android-client/ailib/src/main/java/ai/api/ui/AIButton.java

@Override
protected void onClick(final View v) {
    super.onClick(v);

    if (aiService != null) {
        switch (currentState) {
            case normal:
                aiService.startListening();
                break;
            case busy:
                aiService.cancel();
                break;
            default:
                aiService.stopListening();
                break;
        }
    }

}

Из нашего обсуждения видно, что вы боретесь с тем, как реализовать это.

Пожалуйста, изучите это apiai-android-client/ Android SDK для api.ai/ Tutorial< /а>

Вернитесь к основам. Забудьте на время о ai.api и изучите основы. Просмотрите документацию Входные события читайте вопросы и применяйте принципы программирования. Например:
Переопределение кнопки Android при нажатии

Кроме этого, я больше ничем не могу вам помочь.

person Community    schedule 10.09.2017

Вы должны сделать одну следующую вещь при отмене AsyncTask. на вашем методе нажатия кнопки.

public void AIButtonClick(View view){
  asyncTask.cancel(false);
}

и проверьте в doInBackground, если он отменен, а затем вернитесь из него.

    @Override
    protected String doInBackground(String... params) {     
     if(asyncTask.isCanceled()) return;
   }

Также в вашем методе onPause у вас есть отмена, это было хорошо.

@Override
public void onPause() {
    super.onPause();
     if(asyncTask!=null){
      asyncTask.cancel(false);

   }
}
person Muazzam A.    schedule 14.09.2017

Попробуйте установить resultListener для вашего AIButton и реализовать метод onCancelled(), отменяющий ваши AsyncTasks оттуда.

Чтобы пометить AsyncTask как необходимое для остановки, вы должны позвонить

asyncTask.cancel(false);

И в вашем AsyncTask вы должны периодически проверять, было ли оно отменено или нет, вызывая isCancelled(). Если этот метод возвращает true, вы должны остановить выполнение.

person algrid    schedule 10.09.2017
comment
как я могу установить прослушиватель результатов для AIButton? - person Hammad Nasir; 11.09.2017
comment
@HammadNasir, вы уже установили его: listenButton.setResultsListener(this);. - person algrid; 11.09.2017
comment
Хорошо! Так что мне просто нужно поместить asyncTask.cancel(false); в onCancelled AIButton, а затем проверить, было ли оно отменено в AsyncTask? - person Hammad Nasir; 12.09.2017

если вы хотите отменить класс AsyncTask translate.cancel()

если вы хотите отменить запрос сервера, я рекомендую использовать OKHTTP, имеет функцию отмены запроса

person Mortada    schedule 16.09.2017