2012-07-12 74 views
3

我必須填寫ListView,並附上需要時間收集的文字信息。 我的方法是使用AsyncTask完成後臺任務,但是當結果到達時將文本設置爲TextView會減慢列表的速度:每次調用getView()時,列表都會滯後。如何異步設置TextView的文本?

這是我的AsyncTask

private class BreadcrumbTask extends AsyncTask<FFile, Void, String>{ 
    private WeakReference<TextView> mTextView; 
    public BreadcrumbTask(TextView textView){ 
     mTextView = new WeakReference<TextView>(textView); 
    } 

    @Override 
    protected String doInBackground(FFile... params) { 
      // text processing 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     if (mTextView != null){ 
      TextView tv = mTextView.get(); 
      if (tv != null) 
       //this line blocks the UI. if I comment it the lag is gone 
       tv.setText(result); 
     } 

// mTextView.setText(結果); }

我在getView()中創建了一個新任務,並執行它。 這個問題顯然來自tv.setText(result)onPostExecute()。當我很好地評論清單流。那麼我如何更新TextView而不會減慢用戶界面呢?

+0

檢查到如何/你在哪裏做的AsyncTask .execute(),如果在你的ListView適配器getView,這可能會在每個視圖中被調用多次。也許你的getView和AsyncTask中的一些日誌代碼會有所幫助。 tv.setText()本身肯定會讓你感到厭倦。 – CSmith 2012-07-12 18:04:52

+0

@NathanZ你有沒有得到這個決議? – bugfixr 2014-11-28 19:08:22

回答

0

你不能從另一個線程更新UI。但是您可以使用Handler動態更新UI。你的類中定義一個處理程序,並以下列方式使用它:

聲明:

String result = ""; 
Handler regularHandler = new Handler(new Handler.Callback() { 
    public boolean handleMessage(Message msg) { 
     // Update UI 
    if(msg.what==3){ 
    if (mTextView != null){ 
      TextView tv = mTextView.get(); 
      if (tv != null){ 
       //this line blocks the UI. if I comment it the lag is gone 
       tv.setText(result); 
      } 
     } 
    } 
     return true; 
    } 
}); 

你在onPostExecute

@Override 
    protected void onPostExecute(String result) { 
       //store the value in class variable result 
       this.result = result; 
       handler.sendEmptyMessage(3); 
     } 
+0

我不應該這樣做,因爲onPostExecute()在UI線程上運行 – znat 2012-07-12 17:46:28

+0

正確。並非所有視圖都有自己的內置處理程序,因此您可以輕鬆完成tv.post(new Runnable(){...});.不過,你說得對,在這種情況下不需要。 – 2012-07-12 18:20:36

+0

WeakReference的使用非常聰明,但這可能是問題的原因嗎? – 2012-07-12 18:21:10

1

使用代碼ViewHolder模式。

http://developer.android.com/training/improving-layouts/smooth-scrolling.html

保持查看視圖中的持有人對象

您的代碼可能的ListView的滾動,這會降低性能時經常致電findViewById()。即使適配器返回回收的充氣視圖,您仍然需要查找元素並進行更新。圍繞重複使用findViewById()的方法是使用「視圖持有者」設計模式。

一個ViewHolder對象中的每個佈局的標籤 領域內組件的意見,這樣你就可以立即而不 需要反覆看看他們訪問他們的商店。首先,你需要創建一個類到 保持你的確切的一套意見。例如:

static class ViewHolder { 
    TextView text; 
    TextView timestamp; 
    ImageView icon; 
    ProgressBar progress; 
    int position; 
} 

然後填充ViewHolder並將其存儲裏面的佈置。

ViewHolder holder = new ViewHolder(); 
holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image); 
holder.text = (TextView) convertView.findViewById(R.id.listitem_text); 
holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp); 
holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner); 
convertView.setTag(holder); 

一些其他的例子:

http://xjaphx.wordpress.com/2011/06/16/viewholder-pattern-caching-view-efficiently http://www.jmanzano.es/blog/?p=166

+0

非常感謝Akos,但我已經在使用視圖持有者 – znat 2012-07-12 17:45:53

0
@Override 
protected void onPostExecute(String result) { 

if (mTextView != null){ 
     TextView tv = mTextView.get(); 
     if (tv != null) 
      //this line blocks the UI. if I comment it the lag is gone 
      tv.setText(result); 

} 
+2

'onPostExecute()'已經在UI線程上執行了。這什麼都不做。 – kcoppock 2012-07-12 17:39:45