从 AsyncTask 返回位图文件会冻结 UI 个线程

Returning a bitmap file from AsyncTask freezes UI thread

我创建了一个简单的 Activity。 activity 负责从 parse.com 数据库下载数据并填充线性布局。在此过程中,我根据内容使用 TextViews 和 ImageViews 动态创建线性布局。

问题是,每当我尝试下载图像时,我都会使用 AsyncTask 下载 class,这会导致 UI 线程变慢!我目前正在尝试 return 来自 AsyncTask 图像的位图文件下载 class 使用: returnedBitmap = new LoadImage().execute(src).get(); 这可能会减慢 UI 线程。我必须这样做,因为调用方方法 geneterImageView 在接收到位图文件时将 return 图像视图。

完整的Activity代码:

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("xyz@xyz.com", "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){
        }

    }

}

是否有任何替代方法可以替代从 AsyncTask 获取位图并将其设置在图像视图中?是否应该对方法进行逻辑更改?

不要在 AsyncTask 上调用 get() 方法,它会使主线程等待 AsyncTask 完成。如果你真的想在 AsyncTask 完成后才开始做某事,请将其放入 AsynTask

onPostExecute()

正如其他人所提到的,您的代码存在多个设计缺陷,因此很难为您提供问题的解决方案。

AsyncTask 的全部目的是在后台线程上执行。在主线程上执行网络和位图处理 永远不会工作 。您必须重构您的代码以适应这一点。至少考虑针对此特定问题的以下解决方案:

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

然后您可以执行以下操作:

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

但是,根据您最终创建的 AsyncTask 数量,这可能并不理想。但就是这个想法。

试试这个: 不要调用 get() @praveen。而是在构造函数中传递图像视图引用

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

}