1

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

任何建议都受到高度赞赏。

4

2 回答 2

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

    }

已编辑

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

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

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

有关更多说明,请参阅

在这里,我们使用了同步块来等待 UI 线程完成。

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

于 2013-05-13T13:45:22.923 回答
0

AsyncTask分为onPreExecute()onProgressUpdate()onPostExecute(),所有这些都发生在主 UI 线程中,允许您膨胀视图。只有doInBackground()在另一个线程中实际发生的事情。如果您可以在此方法上进行所有计算并且仅膨胀onProgressUpdate()onPostExecute()可能会有所帮助。此外,如果您可以将您的代码提供给我们,它可能会帮助我们找到一种提高 CPU 效率的方法。

无论如何,如果 UI 线程超过 5 秒没有响应,android 将尝试强制关闭您的应用程序,并且没有什么可做的(据我所知)。

于 2013-05-13T13:24:56.557 回答