kittu88
kittu88

Reputation: 2461

Returning a bitmap file from AsyncTask freezes UI thread

I have created a simple Activity. The activity is responsible for downloading data from parse.com database and populating a linear layout. In the process, I am dynamically creating the linear layout with TextViews and ImageViews according according to the content.

The problem is that, whenever I try to download an image, I use as AsyncTask Downloading class, which results in slowing down the UI thread! I am currently trying to return the bitmap file from the AsyncTask Image downloading class using: returnedBitmap = new LoadImage().execute(src).get(); which might be responsible for slowing down the UI thread. I have to do this because the caller method geneterImageView will return an imageview when it receives the bitmap file.

The complete Activity code:

public class MainActivity extends ActionBarActivity {

    ArrayList<String> heightList = new ArrayList<String>();
    ArrayList<String> reversedList = new ArrayList<String>();
    ImageView imageView1;
    Bitmap bitmap;
    RelativeLayout parent_layout;

    ParseObject user;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // imageView1 = (ImageView)findViewById(R.id.imageView1);
        parent_layout = (RelativeLayout) findViewById(R.id.parent_layout);

        login("[email protected]", "xyz");


    }



    private void loopThroughArrayAndAttach(){
        LinearLayout llInner = new LinearLayout(this);
        llInner.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        parent_layout.addView(llInner);
        for (int i = 0; i < heightList.size(); i++) {

            if (hasNoImagess(heightList.get(i)) == true) {
                // No images.
                TextView myText = geneterTextView(heightList.get(i));
                llInner.addView(myText);
                // geneterTextView(heightList.get(i));

            } else {
                ImageView myImage = geneterImageView(heightList.get(i));
                llInner.addView(myImage);
                // geneterImageView(heightList.get(i));
            }
        }
    }

    public static boolean hasNoImagess(String contents){
        Document doc = Jsoup.parse(contents);
        Element element = doc.body();
        Elements elements = element.select("img");
        if (elements.isEmpty()) {
            return true;
        } else {
            return false;
        }
    }

    public ImageView geneterImageView(String imgContent){
        // Will need to run via background thread - like aysnc
        // Extract the image file via jsoup
        // Insert it into a imagevieww
        // Inser that into a layout.
        Log.d("IN IMAGE ", " " + imgContent);
        Document doc = Jsoup.parse(imgContent);
        Elements img = doc.getElementsByTag("img");
        Bitmap returnedBitmap = null;
        for (Element el : img) {
            String src = el.absUrl("src");
            System.out.println("src attribute is : " + src);
            // new DownloadImageTask((ImageView)
            // findViewById(R.id.imageView1)).execute(src);
            try {
                returnedBitmap = new LoadImage().execute(src).get();
                // imageView1.setImageBitmap(returnedBitmap);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        ImageView iv = new ImageView(this);
        iv.setImageBitmap(returnedBitmap);
        return iv;
    }

    public TextView geneterTextView(String textContent){
        // Will need to run via background thread.
        Log.i("In TEXT ", " " + textContent);
        TextView tv = new TextView(this);
        tv.setText(Html.fromHtml(textContent));
        return tv;
    }

    // to download images
    private class LoadImage extends AsyncTask<String, String, Bitmap> {
        @Override
        protected void onPreExecute(){
            super.onPreExecute();
        }

        protected Bitmap doInBackground(String... args){
            try {
                bitmap = BitmapFactory.decodeStream((InputStream) new URL(args[0]).getContent());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bitmap;
        }

        protected void onPostExecute(Bitmap image){
            if (image != null) {
            } else {
                Toast.makeText(MainActivity.this, "Image Does Not exist or Network Error", Toast.LENGTH_SHORT).show();
            }
        }
    }

    // to login to parse
    private void login(final String username, String password){
        ParseUser.logInInBackground(username, password, new LogInCallback() {
            @Override
            public void done(ParseUser user, ParseException e){

                if (e == null) {
                    // if login sucess
                    // Start intent
                    // loginSuccess();
                    Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
                    CloudCallStudentPosts(user);

                } else {
                    Toast.makeText(MainActivity.this, "Failure", Toast.LENGTH_SHORT).show();
                }
            }
        });

    }

    // //to get data from parse
    public void CloudCallStudentPosts(ParseObject s){

        setRichStory(s);
    }

    private void setRichStory(ParseObject s){
        // Simialr to setStory, once implemented delete setStory()
        new AddStoryAsync(s).execute();
    }

    class AddStoryAsync extends AsyncTask<Void, Object, Void> {

        private static final String TAG = "LazyListView";
        ParseObject s;

        public AddStoryAsync(ParseObject s) {
            this.s = s;
            Log.w("In richStory", "ParseObject Id: " + s.getObjectId());
        }

        @Override
        protected void onPreExecute(){

        }

        @Override
        protected Void doInBackground(Void... unused){
            HashMap<String, Object> params = new HashMap<String, Object>();
            params.put("userid", this.s.getObjectId());
            params.put("skip", 0);
            ParseCloud.callFunctionInBackground("studentsPosts", params, new FunctionCallback<List<List<ParseObject>>>() {
                @Override
                public void done(List<List<ParseObject>> postList, com.parse.ParseException arg1){
                    if (postList == null) {
                    } else {
                        if (postList.size() > 0) {
                            // CustomWebView cwb;
                            for (int i = 0; i < postList.size(); i++) {
                                // final Post post = new Post();

                                if (postList.get(i).get(0).get("htmlContent") == null) {

                                }

                                if (postList.get(i).get(0).get("htmlContent") != null) {
                                    Log.e("htmlContent parse", postList.get(i).get(0).get("htmlContent").toString());
                                    // Parse HTML String using JSoup library
                                    String HTMLSTring = postList.get(i).get(0).get("htmlContent").toString();

                                    Document html = Jsoup.parse(HTMLSTring);

                                    Elements paragraphs = html.getElementsByTag("p");
                                    for (org.jsoup.nodes.Element paragraph : paragraphs) {
                                        String paragraphText = paragraph.toString();
                                        Log.e("paragraphText", paragraphText);
                                        heightList.add(paragraphText);
                                    }

                                    loopThroughArrayAndAttach();
                                }


                            }
                        }
                    }
                }

            });
            return (null);
        }

        @Override
        protected void onProgressUpdate(Object... object){

            Log.w("onProgressUpdate ", " " + object[0].getClass());

            Log.w("adding to arrayPostList ", " " + object[0].getClass());

        }

        @Override
        protected void onPostExecute(Void unused){
        }

    }

}

Is there any substitute for getting the bitmap from the AsyncTask and set it in the imageview? Should there be a logical alteration in the approach?

Upvotes: 1

Views: 969

Answers (3)

KomalG
KomalG

Reputation: 778

try this : dont call get() @praveen. instead pass the imageview Reference in the constructor

WorkerThread mWorkerThread = new WorkerThread(mImageView);
mWorkerThread.execute(src);


private class WorkerThread extends AsyncTask<String, String, Bitmap> {
    private WeakReference<ImageView> imageViewReference;

    public WorkerThread(ImageView imageView) {
        super();
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    @Override
    protected Bitmap doInBackground(String... args) {
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeStream((InputStream) new URL(args[0]).getContent());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        super.onPostExecute(result);
        if (result != null && imageViewReference.get() != null) {
            imageViewReference.get().setImageBitmap(result);
        }
    }

}

Upvotes: 1

Jeffrey Mixon
Jeffrey Mixon

Reputation: 13616

As others have mentioned, your code has several design flaws which makes it difficult to provide you a solution to your problem.

The whole purpose of an AsyncTask is to execute on a background thread. Executing networking and bitmap processing on the main thread will never work. You must refactor your code to accommodate this. Consider the following solution to this particular problem at least:

// to download images
private class LoadImage extends AsyncTask<String, Void, Bitmap> {

    protected Bitmap doInBackground(String... args) {
        String imgContent = args[0];

        Document doc = Jsoup.parse(imgContent);
        Elements img = doc.getElementsByTag("img");

        for (Element el : img) {
            String src = el.absUrl("src");
            System.out.println("src attribute is : " + src);

            try {
                return BitmapFactory.decodeStream((InputStream) new URL(src).getContent());
            } catch (Exception e) {
                // log
            }
        }
        return null;
    }

    protected void onPostExecute(Bitmap b) {
        ImageView iv = new ImageView(MainActivity.this);
        iv.setImageBitmap(b);
        llInner.addView(iv);
    }
}

You can then do something like:

for (int i = 0; i < heightList.size(); i++) {
    new LoadImage(heightList.get(i)).execute();
}

However, this may not be desirable depending on how many AsyncTasks you end up creating. But this is the idea.

Upvotes: 0

Praveena
Praveena

Reputation: 6941

Don't call get() method on AsyncTask it makes main thread to wait for AsyncTask to complete. If you really want to start something only after AsyncTask completes put that into onPostExecute() of your AsynTask

Upvotes: 0

Related Questions