2

I am having some trouble setting the value of an edit text box using the onPostExecute() method of the async task.

The background tasks takes an bitmap input and performs OCR using the Microsoft Vision API and returns the value of the OCR result.

It works on most devices however it fails to work on Galaxy Note 3 running Android 5.0.

The result of the background task can be retrieved and toasted without any errors.

Async Task

private class OCRImg extends AsyncTask<Bitmap, String, String> {
            EditText gluET;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            gluET = (EditText) ((Activity) context).findViewById(R.id.glucoseETm);

        }

        @Override
        protected String doInBackground(Bitmap... params) {
            String finalResult = "";
            try {
                VisionServiceClient client;
                client = new VisionServiceRestClient("xxxx");
                Bitmap bitmap = params[0];

                ByteArrayOutputStream output = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
                ByteArrayInputStream inputStream = new ByteArrayInputStream(output.toByteArray());
                Gson gson = new Gson();

                OCR ocr = client.recognizeText(inputStream, LanguageCodes.English, true);
                String result = gson.toJson(ocr);
                Log.d("result", result);

                if (result != null) {

                    OCR r = gson.fromJson(result, OCR.class);
                    for (Region reg : r.regions) {
                        for (Line line : reg.lines) {
                            for (Word word : line.words) {
                                finalResult += word.text + " ";
                            }
                            finalResult += "\n";
                        }
                        finalResult += "\n\n";
                    }
                }
            } catch (MalformedURLException ex) {
                ex.printStackTrace();
            } catch (ProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                Log.e("Post Error", "multipart post error " + e + "(");
            }
            Log.v("Final OCR Result", finalResult);
            return finalResult;
        }

        @Override
        protected void onPostExecute(String result) {
            try {
                result = result.replaceAll("\\D+", "");
                gluET.setText(result);
                Toast.makeText(context, result, Toast.LENGTH_LONG).show();

            } 
        }
    }

Layout.XML

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/glucoseFrag"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentBottom="true"
    android:background="?android:attr/colorBackground"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="edu.tp.SWEN.GlucoseFragment">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TableLayout

            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/viewPager"
            android:gravity="top"
            android:stretchColumns="0,1">


            <TableRow
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:stretchColumns="0,1">

                <EditText
                    android:id="@+id/glucoseETm"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_span="2"
                    android:ems="10"
                    android:hint="Enter glucose reading (mmol/dl)"
                    android:inputType="numberDecimal"
                    android:singleLine="true" />

                <ImageButton
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:id="@+id/btn_camera"
                    android:src="@drawable/ic_camera_alt_grey_700_18dp"
                    android:background="@color/white"/>
            </TableRow>
        </TableLayout>

    </ScrollView>

</FrameLayout>

Method calling the async task

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 4;
            glucose = (EditText) view.findViewById(R.id.glucoseET);
            Bitmap bitmap = (Bitmap) data.getExtras().get("data");
            new OCRImg().execute(bitmap)
}
}

EDIT Looking at the stack trace I see this line appearing on the phones that cannot set the text. It doesn't appear on phones that can setText().

`0`6-2`3 14:09:21.339 10547-10547/com.test.app W/FileUtils: Failed to chmod(/storage/emulated/0/com.test.app/SWEN): android.system.ErrnoException: chmod failed: EPERM (Operation not permitted)`
Isaac
  • 310
  • 5
  • 16

3 Answers3

1

You can try passing in your EditText to the AsyncTask when you call it:

YourTask yourAsyncTask = new YourTask(YourEditText);
yourAsyncTask.execute(DoInBgParams);

Then, assign it to a member variable in your AsyncTask:

EditText mYourEditText;

public YourTask(Editext editText){
    mYourEditText = editText;
}

...
@Override
protected void onPostExecute(String result) {
    mYourEditText.setText(result);
}
Sammy T
  • 1,924
  • 1
  • 13
  • 20
0

Make sure you're always calling AsyncTask.execute on the main thread. See this thread where other people have ran into oddities as a result.

Community
  • 1
  • 1
Austin Hanson
  • 21,820
  • 6
  • 35
  • 41
  • The async task is running in the main thread in the onActivityResult() – Isaac Jun 23 '16 at 05:00
  • When you say "fails to work on ..." - it just doesn't doesn't set the text? Also, out of curiosity, why do you store a reference to the EditText in onPreExecute rather than just grabbing it in onPostExecute when you call it? – Austin Hanson Jun 23 '16 at 05:07
  • Yeah it doesn't set the text. While researching the problem there was a solution that put the edit text in the onPreExecutre(). It was initially in the onPostExecute() – Isaac Jun 23 '16 at 05:41
  • Is it possible you're setting the text somewhere else and overwriting it? Have you tried grabbing the text, after setting it, and checking if it's the value you set? Do you have multiple EditTexts on the screen with the same ID and are just setting the wrong one? Why do you have it in a try {} without a catch? – Austin Hanson Jun 23 '16 at 14:54
-2

In onPostExecute, you should use runOnUIThread to update the UI.

onPostExecute is executed when the background task running is done.

On some devices, maybe the UI thread is not ready when the background task is done. Maybe the main thread is locked...

EDIT

Also look if onCancelled is called instead of onPostExecute and log the error.

Alexandre Martin
  • 1,472
  • 5
  • 14
  • 27
  • Alexandre, `onPostExecute` method execute on Main UI Thread, so no need to use `runOnUIThread ` to update UI from `onPostExecute` – ρяσѕρєя K Jun 23 '16 at 04:31
  • But since AsyncTask has onPostExecute method (which also runs on UI thread) so you dont logically need to use runOnUiThread there. – Riten Jun 23 '16 at 04:32
  • That is not right. onPostExecute cares about the running task, not the UI. It can update it, but cannot get its status – Alexandre Martin Jun 23 '16 at 04:33
  • onPostExecute is innvoked on the UI thread after the background computation finishes – Riten Jun 23 '16 at 04:34
  • It is, but if the UI thread is not ready, it will throws an error – Alexandre Martin Jun 23 '16 at 04:35
  • IIRC, onPostExecute is executed on the thread which called AsyncTask.execute, as with all of the onXxxExecute methods. But...I can't recall where I observed that or read it. So... I could be wrong. – Austin Hanson Jun 23 '16 at 04:46
  • You are right, Austin. But if the task is launched and executed before the EditText is inflated and onPostExecute tries to update the View, it will crash. That is why I said onPostExecute can modify the UI, but doesn't know when the View is ready – Alexandre Martin Jun 23 '16 at 04:51
  • That's a different issue. The UI thread is "ready" but the view might not exist in the view hierarchy. runOnUiThread could still execute prior to the view inflating. You could trivially continue calling runOnUiThread until the view inflates, set an inflation listener, or just wait to call the AsyncTask until it has inflated. – Austin Hanson Jun 23 '16 at 04:54