-->

API.AI: How to stop AsyncTask on click of the AIBu

2020-03-20 04:45发布

问题:

I’m using AIButton in my app and I have a AsyncTask which gets executed after AIButton is clicked and receives some command and AsyncTask sometimes takes too long to execute.

Here’s my code:

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);

Here's the 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();
            }
        }
    }

I'm calling above given AsyncTask in onResult() method like this:

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;
                    }
                }
            }
        }

    });

}

So, what I want is to stop all running AsyncTask when the AIButton is clicked so that previous tasks are stopped in order to execute new task. How to do this?

The problem here is that you can't do something like: listenButton.onClickListener() here.

回答1:

Use boolean cancel (boolean mayInterruptIfRunning).

Make the asyncTask a class variable.

AsyncTask translate_ = new translate();

Then call it like so in place.

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

Within the button onclick cancel the asyncTask.

translate_.cancel(true);

Then check within your loop that the task has been cancelled and set a break.

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

These questions also give some more variety in how to choose to do this:

Android - Cancel AsyncTask Forcefully

How to stop asynctask thread in android?

It would be wise to manage the task on backpress also. Perhaps cancel the task in the activity onpause.

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;
}

Or cancel the task when the aiservice is cancelled or stopped.

@Override
public void onListeningStarted() {}

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

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

There's other ways it can be managed, explore your options. Have a good look at this and the SO questions linked above.

If you have a look at the docs.

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;
        }
    }

}

It's clear from our discussion you're struggling with how to implement this.

Please study this apiai-android-client/ Android SDK for api.ai/ Tutorial

Go back to the basics. Forget about the ai.api for a while and learn the basics. Browse around, read the docs Input Events read questions and apply the programming principles. For example:
Android button onclick override

Beyond this I cannot help you any further.



回答2:

You have to do one following thing when canceling AsyncTask. on your button click method.

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

and check in doInBackground if it's canceled then return from it.

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

Also on in your onPause method you have cancel it was well.

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

   }
}


回答3:

Try to set resultListener for your AIButton and implement onCancelled() method canceling your AsyncTasks from there.

To mark an AsyncTask as required to stop you should call

asyncTask.cancel(false);

And in your AsyncTask you have to check periodically whether it was cancelled or not by calling isCancelled(). If this method returns true you should stop execution.



回答4:

if you want to cancel the AsyncTask class translate.cancel()

if you want to cancel the server request I recommend to use OKHTTP has a cancel request feature