在后台从视图创建位图

时间:2013-05-13 13:05:56

标签: android android-asynctask layout-inflater

在我的Android应用程序中,对于某个活动,我需要创建视图的屏幕截图而不实际显示它们。我通过膨胀视图并将其保存为位图来成功实现这一目标。 但在某些情况下,这些位图的数量足够大,创建它们需要花费大量时间。因此,手机上的UI变得无响应。有什么方法可以在后台完成整个过程吗?我已经尝试在异步任务中实现它,但这不起作用,因为它不允许在异步任务中膨胀视图。

非常感谢任何建议。

2 个答案:

答案 0 :(得分:2)

AsyncTask doBackground方法适用于另一个线程,这就是你无法扩充视图的原因。

首先是你有一个布局还是多个布局。如果您有很多,请尝试以下。

我没有测试过这个。只是一个样品给你。

public class Task extends AsyncTask<Void, Integer, Void>
    {
        private ArrayList<Integer> layoutIds;
        private View currentView;
        private LayoutInflater inflater;
        private Object lock = new Object();

        public Task(Context context) {
            super();
            inflater = LayoutInflater.from(context);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... params) {

            Bitmap temp;

            for (int i = 0; i < layoutIds.size(); i++) {

                temp = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
                Canvas canvas = new Canvas(temp);

                synchronized (lock) {
                    publishProgress(i);

                    try {
                        // Wait for the UI Thread to inflate the layout.
                        lock.wait();
                    }
                    catch (InterruptedException e) {

                    }
                }

                currentView.draw(canvas);

                // Now save this bitmap
                try {
                    FileOutputStream stream = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "File_" + i + ".png"));
                    temp.compress(Bitmap.CompressFormat.PNG, 100, stream);
                    stream.flush();
                    stream.close();
                } catch (Exception e) {

                }
                finally
                {
                    if(temp != null)
                    {
                        temp.recycle();
                        temp = null;
                    }
                }
            }

            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            synchronized (lock) {
                currentView = inflater.inflate(layoutIds.get(values[0]), null);
                // Notify async thread that inflate is done. 
                lock.notifyAll();
            }
        }

    }

<强> EDITED

这里我们有两个第一个线程是AsyncTask,它是一个线程池,另一个是UI线程。

使用synchronized块,我们可以确保只有一个线程可以使用对象锁,只要它没有处于休眠或等待另一个线程。

因此,如果一个线程正在同步中执行块,那么它将开始监视该对象,并确保不会执行其他具有该对象的同步块的线程。即,只要活动线程进入休眠状态或在同步块内完成其执行,另一个线程就必须等待。

有关详细说明,请参阅this

在这里,我们使用synchronize块等待UI线程完成。

因此,当它执行lock.wait()时,AsyncThread将等到另一个线程调用同一对象上的notify。当调用lock.notifyAll()时,所有正在等待的线程(AsyncThread)将被恢复。

答案 1 :(得分:0)

AsyncTask分为onPreExecute()onProgressUpdate()onPostExecute(),所有这些都发生在主UI线程中,允许您对视图进行充气。只有doInBackground()才是其他线程中实际发生的事情。如果您可以对此方法进行计算,只会使onProgressUpdate()onPostExecute()膨胀,则可能有所帮助。 此外,如果您可以向我们提供您的代码,它可能有助于我们找到一种方法来提高CPU效率。

无论如何,如果UI线程的响应时间超过5秒,android将尝试强制关闭你的应用程序,并且就此而言并不多了(据我所知)。