12

I have a GoogleTranslate.java file that has a class, GoogleTranslate, that extends AsyncTask. The purpose of this task is to perform Google translations.

I have another class, MyVocab, that allows the user to input a word to translate in an alert dialog. So on a click to the alert dialog button, the word will be translated to the desired language by calling on the GoogleTranslate class. However, when I pass a progress bar from MyVocab to GoogleTranslate it doesn't work. When the operation is running (for an observable amount of time), the progress bar doesn't show. I set the progress bar as VISIBLE in onPreExecute and set it as GONE in onPostExecute.

I'm wondering if it's because I have GoogleTranslate and MyVocab in two different java files since most of the examples I see have async class and the class that calls it in the same java file. Please let me know if there's anything I'm doing wrong that's causing this problem.

Here's the related code:

GoogleTranslate.java

public class GoogleTranslate extends AsyncTask<String, Void, String>{

private ProgressBar mProgressBar;

public GoogleTranslate(ProgressBar progressBar) {
    super();
    mProgressBar = progressBar;
}

@Override
protected void onPreExecute() {
    mProgressBar.setVisibility(View.VISIBLE);
}

@Override
protected void onPostExecute(String s) {
    mProgressBar.setVisibility(View.GONE);
}

@Override
protected String doInBackground(String... params) {
    String vocab = params[0];
    String source = params[1];
    String target = params[2];

    String sourceQuery = "";
    String targetQuery = "&target=" + target;

    // "" means its
    if (!source.equals("Detect Language")) {
        sourceQuery = "&source=" + source;
    }

    try {
        String APIKey = "MY_API_KEY";
        String encodedQuery = URLEncoder.encode(vocab, "UTF-8");
        URL url = new URL("https://www.googleapis.com/language/translate/v2?key=" +
                APIKey +
                "&q=" +
                encodedQuery +
                sourceQuery +
                targetQuery);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }
            bufferedReader.close();
            return stringBuilder.toString();
        }
        finally {
            urlConnection.disconnect();
        }
    }
    catch (Exception e) {
        return null;
    }
}

}

Parts of method from MyVocab:

protected void addVocabAlertDialog(final VocabDbHelper dbHelper, final String category,
                                 final VocabCursorAdapter cursorAdapter) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Add Vocab");

    LayoutInflater li = LayoutInflater.from(CategoryItem.this);
    View promptsView = li.inflate(R.layout.alert_dialog_add_vocab, null);
    final EditText vocabInput = (EditText) promptsView.findViewById(R.id.vocabInput);
    final EditText definitionInput = (EditText) promptsView.findViewById(R.id.definitionInput);
    final ProgressBar progressBar = (ProgressBar) promptsView.findViewById(R.id.progressBar);
    builder.setView(promptsView);

    final GoogleTranslate googleTranslate = new GoogleTranslate(progressBar);
    // Set up the buttons
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            String vocab = vocabInput.getText().toString();
            String definition = definitionInput.getText().toString();
            dbHelper.insertVocab(category, vocab, definition, 0);
            if (!category.equals(VocabDbContract.CATEGORY_NAME_MY_WORD_BANK)) {
                dbHelper.insertVocab(VocabDbContract.CATEGORY_NAME_MY_WORD_BANK, vocab, definition, 0);
            }
            // Update Cursor
            Cursor cursor = dbHelper.getVocabCursor(category);
            cursorAdapter.changeCursor(cursor);
        }
    });
    final AlertDialog dialog = builder.create();

    dialog.show();

    dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String vocab = vocabInput.getText().toString();

            SharedPreferences sharedPreferences = getSharedPreferences("Translation", MODE_PRIVATE);
            int sourcePos = sharedPreferences.getInt("Source", 0); // 0 is for Detect Language
            int targetPos = sharedPreferences.getInt("Target", 19); // 19 is for English

            String source = LanguageOptions.FROM_LANGUAGE_CODE[sourcePos];
            String target = LanguageOptions.TO_LANGUAGE_CODE[targetPos];

            final AlertDialog.Builder builder = new AlertDialog.Builder(CategoryItem.this);
            builder.setMessage("Network is unavailable. Please try again later.");
            builder.setNegativeButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });
            AlertDialog dialog = builder.create();

            if (isNetworkAvailable()) {
                AsyncTask<String, Void, String> asyncTask = googleTranslate.execute(vocab, source, target);
                try {
                    String translatedJSON = asyncTask.get();
                    JSONParser jsonParser = new JSONParser();
                    String translatedText = jsonParser.parseJSONForTranslation(translatedJSON);
                    definitionInput.setText(translatedText);
                } catch (Exception e) {
                    dialog.show();
                }
            }
            else {
                dialog.show();
            }
        }
    });

}

XML file that contains progress bar:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Vocab"
    android:id="@+id/vocabInput"
    android:inputType="textAutoComplete"/>

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Definition"
    android:id="@+id/definitionInput"
    android:inputType="textAutoComplete"
    android:layout_below="@+id/vocabInput"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true" />

<ProgressBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:visibility="gone"
    android:indeterminate="true"
    android:id="@+id/progressBar"/>

Charles Li
  • 1,835
  • 3
  • 24
  • 40
  • Is your first dialog still visible while the async task does its job? – natario Jul 11 '16 at 22:37
  • Yup it's still visible. When I click the "translate" (neutral) button, it appears to stay pushed (button has shades that indicate being pressed) until the translation operation is done. The dialog is designed to keep open during and after the translation operation. – Charles Li Jul 11 '16 at 23:19
  • A quick (stupid) check: is your theme colorAccent different from your progress bar background? Because progressBar default color the colorAccent... – Federico De Gioannini Jul 26 '16 at 17:57
  • Yup! I was able to make it show if I just set the progress bar VISIBLE without ever setting it to either GONE or INVISIBLE, so that's not the problem. Thanks for your input! – Charles Li Jul 27 '16 at 03:14
  • 1
    I just tested your GoogleTranslate class and the progress bar works perfectly for me. At first I did't saw the progress because I had an exception so the task ended immediately. In order to see the progress bar anyway, I just added a delay in the post execute: `@Override protected void onPostExecute(String s) { new Handler().postDelayed(new Runnable() { @Override public void run() { mProgressBar.setVisibility(View.GONE); } },3000); }` Can you please try this in order to exclude that the task is to quick? – Federico De Gioannini Jul 27 '16 at 07:19
  • Hello Federico, thanks for your time! I actually used the slowest internet connection setting in my emulator (tried two different emulators) so the operation takes at least 3 or 4 seconds to run. However, it still didn't show anything. When the process is running for that period of time, the button just stays slightly grayed out and appeared to be pushed throughout the duration of the translation operation. – Charles Li Jul 27 '16 at 13:02
  • So the progress bar works perfectly for you now? It appears when you hit the button and disappears when the operation is completed? – Charles Li Jul 27 '16 at 13:03
  • actually I just ran the operation again, it takes at least 6 to 7 seconds for the translation operation to complete. – Charles Li Jul 27 '16 at 13:14
  • And I just updated the code so that it passes the progress bar using the GoogleTranslate class constructor instead. Still no difference to the results btw. – Charles Li Jul 27 '16 at 15:06
  • And I'm not sure why but it seems like I can directly set the visibility of the progress bar (just for testing) outside of the onClick method but just not in it. – Charles Li Jul 27 '16 at 15:07

6 Answers6

5

I'd suggest using ProgressDialog instead.

I switched from ProgressBar because I faced a similar issue, even after programmatically creating one in the default constructor of my AsyncTask.

public class GoogleTranslate extends AsyncTask<String, Void, String> {
    private ProgressDialog mProgressDialog;
    private Context mContext;

    public GoogleTranslate(Context context) {
        mContext = context;
    }

     @Override
     protected void onPreExecute() {

         mProgressDialog = ProgressDialog.show(
                mContext,
                "Please wait", // Title
                "Translating", // Message
                true           // Indeteriminate flag
         );
     }

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

     @Override
     protected void onPostExecute(String s) {
         if (mProgressDialog != null) {
              mProgressDialog.dismiss();
         }
         ...
     }
 }

Call this AsyncTask like this:

new GoogleTranslate(getActivity() /* or getContext() */).execute(vocab, source, target);
adhirajsinghchauhan
  • 625
  • 1
  • 7
  • 16
  • Thank you for your suggestion! I actually was thinking about this option as well. However, the official Android document says "Avoid ProgressDialog | Android includes another dialog class called ProgressDialog that shows a dialog with a progress bar. However, if you need to indicate loading or indeterminate progress, you should instead follow the design guidelines for Progress & Activity and use a ProgressBar in your layout." so I'm seeing if I can still proceed with ProgressBar unless there's no way to fix it. Thanks again! – Charles Li Jul 25 '16 at 14:18
  • 1
    @Charles Li Well, the Android documentation are merely guidelines to follow. I was stuck for 3 days trying to solve the `ProgressBar` issue, until I finally decided to go with `ProgressDialog` (I read the documentation and had the same thoughts as you do now). I'd suggest you wait for a few days, if you still don't find a solution that works, go with `ProgressDialog` :) – adhirajsinghchauhan Jul 26 '16 at 17:04
  • Yup! That's what I have in mind as well! This is my last effort to find a solution. lol Thanks so much for your input! – Charles Li Jul 27 '16 at 03:16
4

add this before executing the googleTranslate :

 progressBar.setVisibility(View.VISIBLE);
 progressBar.setProgress(0);
 AsyncTask<String, Void, String> asyncTask = googleTranslate.execute(vocab,source, target);

and also implement the onProgressUpdate in googleTranslate.

this link may help :

http://www.concretepage.com/android/android-asynctask-example-with-progress-bar

mehd azizi
  • 594
  • 1
  • 5
  • 16
  • Thank you for your input. However when I added the two lines of code as you suggested, nothing changes. I just posted my xml file for alert dialog that contains the progress bar. It's a circular progress bar (nondeterminate) which is the reason I didn't implement onProgressUpdate. Do I still have to implement onProgressupdate in this case? Because the example provided I believe is for a determinate progress bar. Thanks! – Charles Li Jul 11 '16 at 22:30
  • Do you add ` android:indeterminate="true" ` to your xml for progress bar ? – mehd azizi Jul 12 '16 at 05:53
  • I didn't have it before but even when I add it now, there's no changes. By the way, with my current xml (with or without indeterminte="true"), by setting its default visibility to "visible" in the xml will have the indeterminate progress bar show up as I want to, so the problem is simply with controlling the timing that it appears. Thanks for your help! – Charles Li Jul 12 '16 at 16:17
  • I'm thinking that is it possible that since Java is pass by value that the way I set the progress bar by doing it in the GoogleTranslate class is incorrect. Still experimenting with different ways – Charles Li Jul 12 '16 at 16:19
4

Try to avoid the AsyncTask get() method and use a listener instead. You should update your code this way:

1) In your googleTranslate class, add a listener:

private Listener listener;

    public interface Listener{
        void onTaskResult(String string);
    }

    public void setListener(Listener listener){
        this.listener = listener;
    }

and call it in your onPostExecute:

 @Override
    protected void onPostExecute(String s) {
        if (listener!=null){ listener.onTaskResult(s); }
                mProgressBar.setVisibility(View.GONE);

    }

2) update your main class replacing the get with the listener management, replacing this:

AsyncTask<String, Void, String> asyncTask = googleTranslate.execute(vocab, source, target);
                try {
                    String translatedJSON = asyncTask.get();
                    JSONParser jsonParser = new JSONParser();
                    String translatedText = jsonParser.parseJSONForTranslation(translatedJSON);
                    definitionInput.setText(translatedText);
                } catch (Exception e) {
                    dialog.show();
                }

with this:

googleTranslate.setListener(new GoogleTranslate.Listener() {
            @Override
            public void onTaskResult(String string) {
                    String translatedJSON = string;
                    JSONParser jsonParser = new JSONParser();
                    String translatedText = jsonParser.parseJSONForTranslation(translatedJSON);
                    definitionInput.setText(translatedText);
            }
        });
        googleTranslate.execute(vocab, source, target);

I hope it helped.

  • 1
    Thank you so much for your help throughout this time Federico! Took me some time to understand your code but it makes sense to me now and it works! Now I need to take a deeper look into asynctask.get! Thanks again! – Charles Li Jul 28 '16 at 14:38
3

Try passing ProgressBar as constructor argument of GoogleTranslate class.

karan vs
  • 3,044
  • 4
  • 19
  • 26
3

Add progress bar in your onPreExecute method and hide it in onPostExecute.

private class MyAsyncThread extends AsyncTask<Void, Void, String>
{
            @SuppressWarnings("finally")

            @Override
            protected String doInBackground(Void... params) {
                // TODO Auto-generated method stub
                try {

                // your code

                }
                catch (Exception e) {
                    // TODO: handle exception
                }
                finally
                {

                    return "OK";

                }

            }
            @Override
            protected void onPostExecute(String result) {
                // TODO Auto-generated method stub
                super.onPostExecute(result);

               if (progressDialog != null) {
                   progressDialog.dismiss();
                   progressDialog = null;
               }

                        }catch (Exception e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }
            }


            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                progressDialog = ProgressDialog.show(this, null, "Please wait....");
            }
Gevaria Purva
  • 552
  • 5
  • 15
2

That's because you are blocking Main Thread by asyncTask.get() call, so no UI operations can run until asyncTask completes.

Remove this call and process the asyncTask's results in its onPostExecute(String s) and onCancelled() callbacks instead.

Anton Malyshev
  • 8,686
  • 2
  • 27
  • 45