2013-05-13 58 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