2013-05-13 31 views
1

在我的android应用程序中,在某个活动中,我需要创建视图的屏幕截图而不实际显示它们。我通过夸大观点并将它们保存为位图来成功实现这一目标。 但是在某些情况下,这些位图的数量足够大,需要花费很多时间来创建它们。因此,手机上的用户界面变得无法响应。有什么办法可以在后台完成整个过程吗?我已经尝试过在异步任务中实现它,但这不起作用,因为它不允许在异步任务中对视图进行充气。从背景中创建位图

任何建议,非常感谢。

+0

这些意见已经在背景中夸大了吗?如果是这样,你可能只是得到绘图缓存 – Guardanis 2013-05-13 13:15:42

回答

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

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

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

+0

感谢您对Vivek的快速响应。将尝试你的解决方案,看看它是否工作。 – Anuj 2013-05-13 16:46:51

+0

今天早上我尝试了你的解决方案。在我的实现中唯一缺少的是使用同步锁。你能否在这种情况下解释它的意义? – Anuj 2013-05-14 05:30:03

0

AsyncTask分为onPreExecute(),onProgressUpdate()onPostExecute(),全部发生在主UI线程中,允许您膨胀视图。只有doInBackground()是事实上发生在另一个线程中的地方。如果你可以用这种方法进行计算,只需要膨胀onProgressUpdate()onPostExecute()它可能会有帮助。 另外,如果你可以给我们你的代码,它可能会帮助我们找到一种方法来提高CPU的效率。

总之,Android将尝试强制关闭应用,如果UI线程不响应时间超过5秒,那里有没有太大怎么办呢(据我所知)。

+0

Aviel,我已经尝试在'onProgressUpdate'和'onPostExecute'中进行膨胀,正如你正确地提到Android试图在5秒后强制关闭应用程序。 – Anuj 2013-05-13 17:08:48