sgrumo sgrumo - 4 months ago 69
Android Question

Cardboard sample, method must be called from UI thread

Trying to develop an app for google cardboard, i downloaded the sample from the official sdk. In the inner class ImageLoaderTask ( which it should be the helper class to manage threading )

class ImageLoaderTask extends AsyncTask<Pair<Uri, Options>, Void, Boolean> {

/**
* Reads the bitmap from disk in the background and waits until it's loaded by pano widget.
*/
@Override
protected Boolean doInBackground(Pair<Uri, Options>... fileInformation) {
Options panoOptions = null; // It's safe to use null VrPanoramaView.Options.
InputStream istr = null;
if (fileInformation == null || fileInformation.length < 1
|| fileInformation[0] == null || fileInformation[0].first == null) {
AssetManager assetManager = getAssets();
try {
istr = assetManager.open("andes.jpg");
panoOptions = new Options();
panoOptions.inputType = Options.TYPE_STEREO_OVER_UNDER;
} catch (IOException e) {
Log.e(TAG, "Could not decode default bitmap: " + e);
return false;
}
} else {
try {
istr = new FileInputStream(new File(fileInformation[0].first.getPath()));
panoOptions = fileInformation[0].second;
} catch (IOException e) {
Log.e(TAG, "Could not load file: " + e);
return false;
}
}

panoWidgetView.loadImageFromBitmap(BitmapFactory.decodeStream(istr), panoOptions);
try {
istr.close();
} catch (IOException e) {
Log.e(TAG, "Could not close input stream: " + e);
}

return true;
}
}


panoWidgetView is the widget for the panorama, and it is declared inside the activity which includes this inner class.
But Android Studio gives me this error:
Method loadImageFromBitmap must be called from the UI thread, currently inferred thread is worker.
Any possible solution?

Answer

try moving "loadImageFromBitmap" inside onPostExecute :

class ImageLoaderTask extends AsyncTask<Pair<Uri, BitmapFactory.Options>, Void, Boolean> {
        Options panoOptions = null;  // It's safe to use null VrPanoramaView.Options.
        InputStream istr = null;

        /**
         * Reads the bitmap from disk in the background and waits until it's loaded by pano widget.
         */
        @Override
        protected Boolean doInBackground(Pair<Uri, BitmapFactory.Options>... fileInformation) {

            if (fileInformation == null || fileInformation.length < 1
                    || fileInformation[0] == null || fileInformation[0].first == null) {
                AssetManager assetManager = getAssets();
                try {
                    istr = assetManager.open("andes.jpg");
                    panoOptions = new Options();
                    panoOptions.inputType = Options.TYPE_STEREO_OVER_UNDER;
                } catch (IOException e) {
                    Log.e(TAG, "Could not decode default bitmap: " + e);
                    return false;
                }
            } else {
                try {
                    istr = new FileInputStream(new File(fileInformation[0].first.getPath()));
                    panoOptions = fileInformation[0].second;
                } catch (IOException e) {
                    Log.e(TAG, "Could not load file: " + e);
                    return false;
                }
            }

            try {
                istr.close();
            } catch (IOException e) {
                Log.e(TAG, "Could not close input stream: " + e);
            }

            return true;
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
            if( istr!=null && panoOptions!=null){
                 panoWidgetView.loadImageFromBitmap(BitmapFactory.decodeStream(istr), panoOptions);
            }
            super.onPostExecute(aBoolean);
        }
    }