2011-08-28 74 views
13

UPDATE 2011-08-29 如果我刪除NodePickup中的圖像,lagginess消失了。ListView滾動時非常緩慢(使用ViewHolder /回收)

問題是 - 爲什麼?

----

我回來再次在嘗試一些Android開發人員。我有一個「老」的HTC Hero手機躺在身邊,所以我啓動了一個,做了一些更新,現在再次運行Eclipse和其他。

我在設備上運行Android 2.1。

我做了一個非常簡單的測試應用程序,除了顯示一些活動等之外,沒有做任何事情。即使沒有數據庫連接,也不會從任何網絡獲取數據,該應用程序非常緩慢。非常慢。

例如,我有一個ListView與一些自定義佈局項目。當僅添加6-7項目(以便我滾動)時,滾動時它非常慢。另外,我有一些按鈕,轉變活動,也這是非常非常慢:

mButtonListenerUPP = new OnClickListener() { 
    @Override 
    public void onClick(View v) 
    { 
     Intent myIntent = new Intent(BaseActivity.this, ActivityMain.class); 
     BaseActivity.this.startActivity(myIntent); 
    } 
}; 

我想不通爲什麼,所以我只是張貼代碼在這裏,希望有人有一些尖端我=)

Thx!

適配器,NodeRowAdapter

import java.util.ArrayList; 
import java.util.List; 

import android.app.Activity; 
import android.content.Context; 
import android.view.*; 
import android.widget.ArrayAdapter; 

import android.widget.TextView; 

public class NodeRowAdapter extends ArrayAdapter 
{ 
    private Activity context; 
    private ArrayList<Node> mList; 
    private LayoutInflater inflater; 

    NodeRowAdapter(Activity context, ArrayList<Node> objects) 
    { 
     super(context, R.layout.nodepickup, objects); 
     this.context=context; 
     mList = objects; 
     inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    } 

    class ViewHolder 
    { 
     TextView name; 
     TextView time; 
     TextView road; 
     Node node; 
    } 

    public Node getNode(int position) 
    { 
     if (mList != null && mList.size() > position) 
      return mList.get(position); 
     else 
      return null; 
    } 
    public View getView(int position, View convertView, ViewGroup parent) 
    { 
     View view = convertView; 
     ViewHolder holder; 
     if (view == null) 
     { 
      view = inflater.inflate(R.layout.nodepickup, parent, false); 
      holder = new ViewHolder(); 
      holder.name =(TextView)view.findViewById(R.id.name); 
      holder.time =(TextView)view.findViewById(R.id.time); 
      holder.road =(TextView)view.findViewById(R.id.road); 
      view.setTag(holder); 
     } 
     else 
     { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     Node node = mList.get(position); 
     holder.name.setText(node.name); 
     holder.time.setText(node.time); 
     holder.road.setText(node.road); 

     return(view); 
    } 
} 

的主要活動,ActivityMain

public class ActivityMain extends BaseActivity 
{ 
    private NodeRowAdapter _nodeRowAdapter; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     SICApplication._myContext = this; 
     SICApplication._myContext = this; 

     _nodeRowAdapter = new NodeRowAdapter(this, SICApplication.dataHolder_activityMain._nodes); 
     ListView listView1 = (ListView) findViewById(R.id.ListViewNodes); 
     listView1.setOnItemClickListener(new OnItemClickListener() 
     { 
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
      { 
       Node node = _nodeRowAdapter.getNode(position); 
       Log.v("MyApp", "Node=" + node.name); 
      } 
     }); 
     listView1.setAdapter(_nodeRowAdapter); 

    } 

    /* Handles item selections */ 
    public boolean onOptionsItemSelected(MenuItem item) 
    { 
     switch (item.getItemId()) 
     { 
      case R.id.add_item: 
       addNodeItem(); 
       return true; 
     } 
     return false; 
    } 



    private void addNodeItem() 
    { 
     _nodeRowAdapter.add(new Node("Test", "asd asd ", "14:00", 1)); 

    } 
} 

自定義列表項,NodePickup

public class NodePickup extends LinearLayout 
{ 
    public NodePickup(Context context, AttributeSet attributeSet) 
    { 
     super(context, attributeSet); 

     LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     inflater.inflate(R.layout.nodepickup, this); 

     this.setOnClickListener(new OnClickListener() 
     { 
      @Override 
      public void onClick(View v) 
      { 
       AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 
       builder.setMessage("Ajabaja!") 
       .setCancelable(true) 
       .setPositiveButton("JA!", new DialogInterface.OnClickListener() 
       { 
        public void onClick(DialogInterface dialog, int id) 
        { 
         dialog.cancel(); 
        } 
       }); 
       builder.show(); 
      } 

     }); 
    } 
} 

最後,在NodePickup XML佈局

<LinearLayout 
    android:id="@+id/LinearLayout01" 
    android:layout_width="fill_parent" 
    android:layout_height="64dip" 
    android:orientation="horizontal" 
    android:background="@drawable/stateful_background" 
    xmlns:android="http://schemas.android.com/apk/res/android"> 

    <ImageView 
     android:id="@+id/ImageView01" 
     android:layout_width="40dip" 
     android:layout_height="40dip" 
     android:src="@drawable/arrow_up_green" 
     android:background="@android:color/transparent"> 
    </ImageView> 

    <LinearLayout 
     android:id="@+id/LinearLayout02" 
     android:background="@android:color/transparent" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" 
     xmlns:android="http://schemas.android.com/apk/res/android"> 

     <TextView 
      android:text="14:46 (15 min)" 
      android:id="@+id/time" 
      android:textSize="12dip" 
      android:textColor = "#000000" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:background="@android:color/transparent"> 
     </TextView> 

     <TextView 
      android:text="test" 
      android:id="@+id/road" 
      android:textSize="12dip" 
      android:textColor = "#000000" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:background="@android:color/transparent"> 
     </TextView> 

     <TextView 
      android:text="test test" 
      android:id="@+id/name" 
      android:textSize="12dip" 
      android:textColor = "#000000" 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" 
      android:background="@android:color/transparent"> 
     </TextView> 
    </LinearLayout> 
</LinearLayout> 
+0

使用Traceview來確定您的時間正在被佔用。 – CommonsWare

+0

Thx,我試過了。根本沒有告訴我任何事情。也許我錯過了一些。但是,它似乎是ImageView。如果我從NodePickup中刪除它,它的速度會很快 – Ted

回答

16

UPDATE 2011-08-29說明如果刪除的NodePickup形象,11:43走了。

該視圖很難計算應該如何呈現佈局。你發佈的XML沒有多大幫助。如果您移除ImageView,那麼LinearLayout02將佔據父級的所有寬度。但是如果將imageView的標準尺寸和佈局設置在右側,fill_parent會混淆視圖。再次請求imageView的大小以「將邊距向右推」(種類)。就拿下面

提示1

看看我的建議使用的LinearLayout屬性權重。製作imageView fill_parent和LinearLayout(對於寬度)並使用weight屬性進行播放。 這樣做也適用於TextViews的垂直佈局。最好的解決方案應該是將固定的大小放到TextViews思想的高度。 還考慮將頂視圖更改爲RelativeLayout。用標準尺寸製作圖像AlignParentLeft並將LinearLayout02轉換爲RightOf imageView。您將很大程度上減輕ViewGroup的onMeasure。

提示2

看來當文本改變高度的全貌必須reinflated.A共同TECHNIC,以避免它使列表項固定的高度等。因此,listview可以重新使用循環視圖而不需要重新注入。

提示3

給你LinearLayout02的64dp或FILL_PARENT一個固定的高度,因爲你沒有任何左側的空間,但佈局不知道,並儘量每次都重新安排它的自我,因爲文本也是Wrap_content。

另外你說過,如果你移除ImageView,一切都會很快。 如果以上沒有任何影響可以請你試試這個嗎?既然你知道imageView的大小是固定的。

擴展您的imageView並覆蓋requestLayout()方法。

public class MyImageView extends ImageView { 

public PImageView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 

} 

public PImageView(Context context, AttributeSet attrs) { 
    super(context, attrs); 

} 

public PImageView(Context context) { 
    super(context); 

} 

@Override 
    public void requestLayout() { 
     /* 
     * Do nothing here 
     */ 
    } 
} 

現在,將MyImageView小部件包含到您的XML中。

<com.package_name.MyImageView 
     android:id="@+id/ImageView01" 
     android:layout_width="40dip" 
     android:layout_height="40dip" 
     android:src="@drawable/arrow_up_green" 
     android:background="@android:color/transparent"> 
</com.package_name.MyImageView > 
+0

Thx。我不確定,儘管我沒有對代碼做任何事情,但這種遲緩的行爲消失了。有點奇怪,但是......我無論如何都拿走了你的一些指針/提示=) – Ted

+0

這真是令人難以置信,因爲我使用了你的「提示3」,所以我的ListView滾動更加流暢。你怎麼解決這個問題的? /你能解釋爲什麼這樣或者是否有什麼缺點? –

+0

@JohannesStaehlin知道它的尺寸的觀點並不試圖找出它們。用wrap_content它試圖在運行時執行它。 – weakwire

0

加載圖像一次作爲位圖和膨脹之後編程方式將其應用到ImageView的。如果你需要每個項目不同的圖像,你應該異步創建位圖像Android: How to optimize ListView with ImageView + 3 TextViews?

+0

我會盡快查看您的建議=) – Ted

+0

根據我的對象狀態,我將顯示不同的圖像。但是把他們「異步」看成完全沒有必要。它們與應用程序一起打包,不需要下載它們... – Ted

+0

即使圖像是本地的,它們可能也需要一段時間才能加載,例如,當您要顯示聯繫人照片時:它們可能非常大,需要縮小比例。在ListView中,這會導致明顯的滯後。打包的圖像可能應該沒問題,除非你的設備非常慢。 – mattlaabs

0

嘗試使用android:cacheColorHint="#00000000"爲您的列表視圖。爲了提高滾動操作中的繪圖性能,Android框架重用了緩存顏色提示。

參考:developer.android.com文章。

+0

您的意思是#000000 – strange

+0

@strange額外的00表示alpha通道,所以它會透明 –

+0

使用它沒有性能變化。仍然listview滾動較慢。 –

15

在優化我的getView()方法以使用持有者並重用convertView(如果它不爲null)後,我的listview仍然非常滯後。 然後,我已經試過

listView.setScrollingCacheEnabled(false); 

,並解決了它一次。

希望這可以幫助別人。

+0

這幫了我。謝謝! –

+0

我在輸入建議中多次看到它。但從來不知道目的。 +1 –

1

花了一段時間!我嘗試了一切。禁用滾動緩存,viewHolder,cacheColorHint ...但沒有任何工作!

找了好幾個小時後,我發現了萬惡之源!

在我的themes.xml我有一個比例的背景圖片:

<item name="android:windowBackground">@drawable/window_bg</item> 

取出beackground一切後,黃油順利。

我希望這可以幫助別人!

6

我剛剛發現了這個,我想和大家分享一下。

我試過所有提供的解決方案,但沒有任何工作。是什麼原因導致的問題是因爲我使用

mTextView.SetText(theLongString) 
在我的適配器

在我getView方法,我餵我的TextView的視圖中的一個文本的長度。現在,我皺縮我的字符串,列表視圖非常順利:)

+0

我也有同樣的問題!但爲什麼!? (非常感謝你可愛的解決方案!!!:D) – strings95

1

要提高的ListView的性能使用兩個或兩個任何一個 - (簡單實現)

  • ViewHolder
  • 的AsyncTask(獨立線)

如果你有適度的長名單,我建議ViewHolder另有大型列表(如在音樂播放器),我建議您用的AsyncTask一起使用ViewHolder的情況。平滑ListView滾動的關鍵是儘可能減少內存消耗。

要實現ViewHolder,很簡單。只需在自定義適配器中創建一個靜態類,該適配器包含通過findViewById查找的所有視圖。因此,這是它應該如何看 -

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

然後,接下來你需要findViewById任何的這些觀點時,就引用ViewHolder喜歡這個 -

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

這是測試代碼,並取自我的一個項目。然而,原始來源是在這裏 - http://developer.android.com/training/improving-layouts/smooth-scrolling.html

使用ViewHolder列表變得更加平滑。使用AsyncTask稍微複雜一些,但如果希望與ViewHolder一起實現AsyncTask以獲得更流暢的滾動體驗,請檢查鏈接。祝你好運!

0

這可能幫助一些一

如果在您的列表項目有一個形象,你要記住,以減少圖像的質量。加載幾Kb的速度比幾兆更快。

幫我

public Bitmap MakeFileSmaller_ToBitmap(File f) { 
     try { 
      // Decode image size 
      BitmapFactory.Options o = new BitmapFactory.Options(); 
      o.inJustDecodeBounds = true; 
      BitmapFactory.decodeStream(new FileInputStream(f), null, o); 

      // The new size we want to scale to 
      final int REQUIRED_SIZE=200; 

      // Find the correct scale value. It should be the power of 2. 
      int scale = 1; 
      while(o.outWidth/scale/2 >= REQUIRED_SIZE && 
        o.outHeight/scale/2 >= REQUIRED_SIZE) { 
       scale *= 2; 
      } 

      // Decode with inSampleSize 
      BitmapFactory.Options o2 = new BitmapFactory.Options(); 
      o2.inSampleSize = scale; 
      return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); 
     } catch (FileNotFoundException e) { 
      Log.d(TAG, "FILE NOT FOUND "); 
     } 
     Log.d(TAG, "OTHER EXCEPTION"); 

     return null; 
    } 
0

我,而我是使用類似的LinearLayout,RelativeLayout的,CardView不同的佈局在同一個列表視圖項不同的孩子的家長收到了同樣的問題。我通過改變RelativeLayout中的所有視圖來解決這個問題。

使用RelativeLayout作爲主,它的子佈局可能會增加加載每個項目的速度。所以滾動會很順利。

<RelativeLayout 
android:id="@+id/LinearLayout01" 
android:layout_width="fill_parent" 
android:layout_height="64dip" 
android:orientation="horizontal" 
android:background="@drawable/stateful_background" 
xmlns:android="http://schemas.android.com/apk/res/android"> 
<RelativeLayout 
    android:layout_width="40dip" 
    android:layout_height="40dip" 
    android:layout_alignParentTop="true" 
    android:layout_alignParentLeft="true" 
    android:layout_alignParentStart="true" 
    android:id="@+id/relativeLayout"> 
    <ImageView 
     android:id="@+id/ImageView01" 
     android:layout_width="40dip" 
     android:layout_height="40dip" 
     android:src="@drawable/arrow_up_green" 
     android:background="@android:color/transparent"> 
    </ImageView> 
</RelativeLayout> 
<TextView 
    android:text="14:46 (15 min)" 
    android:id="@+id/time" 
    android:textSize="12dip" 
    android:textColor = "#000000" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:background="@android:color/transparent" 
    android:layout_alignParentTop="true" 
    android:layout_toRightOf="@+id/relativeLayout" 
    android:layout_toEndOf="@+id/relativeLayout" /> 
<TextView 
    android:text="test" 
    android:id="@+id/road" 
    android:textSize="12dip" 
    android:textColor = "#000000" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:background="@android:color/transparent" 
    android:layout_below="@+id/time" 
    android:layout_toRightOf="@+id/relativeLayout" 
    android:layout_toEndOf="@+id/relativeLayout" /> 
<TextView 
    android:text="test test" 
    android:id="@+id/name" 
    android:textSize="12dip" 
    android:textColor = "#000000" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:background="@android:color/transparent" 
    android:layout_below="@+id/road" 
    android:layout_toRightOf="@+id/relativeLayout" 
    android:layout_toEndOf="@+id/relativeLayout"/></RelativeLayout> 
0

您可以使用 listview.setScrollingCacheEnabled(假)。當滾動列表視圖的應用程序等待區,然後拋出內存不足(OOM)exception.My解決方案是爲我工作。