2011-08-28 43 views
13

CẬP NHẬT 2011-08-29 Nếu tôi xóa hình ảnh trong NodePickup, độ trễ sẽ biến mất.ListView rất chậm khi cuộn (sử dụng ViewHolder/tái chế)

Câu hỏi đặt ra là - tại sao?

----

Tôi lại cố gắng ra một số Android Dev lần nữa. Tôi có một điện thoại HTC Hero "cũ" nằm xung quanh, vì vậy tôi đã khởi động cái đó lên, đã thực hiện một số cập nhật và hiện đang chạy n lần nữa với Eclipse và phần còn lại.

Tôi có Android 2.1 đang chạy trên thiết bị.

Tôi đã thực hiện một ứng dụng thử nghiệm rất đơn giản mà không làm gì cả, ngoại trừ việc hiển thị một số Hoạt động và như vậy. Mặc dù không có kết nối cơ sở dữ liệu, không có dữ liệu nào được tìm nạp từ bất kỳ mạng nào ứng dụng rất chậm. Rất chậm.

Ví dụ: tôi có một ListView với một số mục bố cục tùy chỉnh. Khi chỉ thêm 6-7 mục (để tôi có được cuộn) nó là cực kỳ chậm khi di chuyển. Ngoài ra, tôi có một số nút mà thay đổi hoạt động và cũng có nghĩa là rất rất chậm:

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

tôi không thể tìm ra lý do tại sao, vì vậy Im chỉ đăng mã ở đây và hy vọng rằng ai đó có một số tip cho tôi =)

Thx!

Các Adapter, 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); 
    } 
} 

Các hoạt động chính, 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)); 

    } 
} 

Các danh sách tùy chỉnh mục, 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(); 
      } 

     }); 
    } 
} 

Và cuối cùng, các NodePickup layout 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

Sử dụng Traceview để xác định thời gian của bạn đang được thực hiện. – CommonsWare

+0

Thx, tôi đã thử điều đó. Didnt nói với tôi bất cứ điều gì cả. Có lẽ tôi đang thiếu somethuing. Tuy nhiên, có vẻ như đó là ImageView thực hiện điều đó. Nếu tôi gỡ bỏ nó từ NodePickup, nó nhanh chóng một lần nữa – Ted

Trả lời

16

CẬP NHẬT 2011/08/29 Nếu tôi xóa hình ảnh trong NodePickup, các lagginess đã biến mất.

Chế độ xem có một thời gian khó xác định cách bố cục sẽ được hiển thị. Các xml bạn đăng không giúp đỡ nhiều. Nếu bạn loại bỏ ImageView thì LinearLayout02 sẽ lấy toàn bộ chiều rộng của bố mẹ. Tuy nhiên, việc có imageView với các kích thước chuẩn và bố cục ở bên phải sẽ fill_parent gây nhầm lẫn cho khung nhìn rất nhiều. Yêu cầu kích thước của imageView một lần nữa để "đẩy lề sang bên phải" (loại).Hãy xem gợi ý của tôi dưới đây

Tip1

sử dụng trọng lượng tài sản LinearLayout. Làm cho imageView fill_parent và LinearLayout quá (cho chiều rộng) và chơi với các thuộc tính trọng số. Làm điều đó cũng cho bố cục dọc với TextViews. Giải pháp tốt nhất là đặt một kích thước cố định lên chiều cao của suy nghĩ của TextViews. Đồng thời xem xét thay đổi chế độ xem hàng đầu thành RelativeLayout. Làm cho hình ảnh với các kích thước chuẩn, AlignParentLeft và đặt ImageLayout02 toRightOf imageView. Bạn sẽ giảm bớt sự hài lòng của ViewGroup rất nhiều.

Tip2

Nó có vẻ như khi văn bản thay đổi chiều cao toàn bộ quan điểm cần phải được reinflated.A technic chung để tránh nó để làm cho danh sách Item cố định chiều cao. Vì vậy, listview có thể tái sử dụng các khung nhìn tái chế mà không cần reinflating.

Tip3

Cho LinearLayout02 bạn một chiều cao cố định 64dp hoặc Fill_Parent vì bạn không có bất kỳ không gian bên trái, nhưng Layout không biết điều đó và cố gắng sắp xếp lại nó tự mỗi lần kể từ khi văn bản cũng là Wrap_content.

Ngoài ra, bạn đã nói rằng nếu bạn xóa mọi thứ thì ImageView lại nhanh. Nếu những điều trên không có hiệu lực bạn có thể thử điều này không? Vì bạn biết rằng kích thước của ImageView là cố định.

Mở rộng hình ảnh của bạnXem và ghi đè 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 
     */ 
    } 
} 

Bây giờ bao gồm tiện ích MyImageView vào XML của bạn như thế.

<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. Im không chắc chắn, các loại lagginess biến mất mặc dù tôi didnt làm bất cứ điều gì để mã. Một chút kỳ lạ, nhưng ... tôi trong mọi trường hợp đã lấy một số con trỏ của bạn/tips =) – Ted

+0

Thật đáng kinh ngạc, hwo mượt mà cuộn ListView của tôi vì tôi đang sử dụng bạn "Mẹo 3". Làm thế nào bạn tìm ra điều này?/Bạn có thể giải thích TẠI SAO nó là như vậy hoặc nếu có bất kỳ hạn chế? –

+0

@JohannesStaehlin quan điểm cho rằng những điều dimentions của nó không cố gắng tìm ra chúng. với wrap_content nó đang cố gắng làm điều đó trong thời gian chạy. – weakwire

0

tải hình ảnh một lần như Bitmap và áp dụng nó vào ImageView lập trình sau khi lạm phát nó. Nếu bạn cần những hình ảnh khác nhau cho mỗi mục, bạn nên tạo ra các file ảnh không đồng bộ như được mô tả trong Android: How to optimize ListView with ImageView + 3 TextViews?

+0

Tôi sẽ xem xét đề xuất của bạn sớm =) – Ted

+0

Tôi ahve hình ảnh khác nhau được hiển thị, tùy thuộc vào trạng thái của đối tượng của tôi. Nhưng để lấy chúng "asynch" có vẻ hoàn toàn không cần thiết. Chúng được đóng gói với ứng dụng, không cần phải tải xuống chúng ... – Ted

+0

Ngay cả khi hình ảnh là địa phương, chúng có thể cần thời gian để tải, ví dụ: khi bạn muốn hiển thị ảnh liên hệ: chúng có thể rất lớn và cần phải thu nhỏ lại. Trong một ListView điều này sẽ dẫn đến tụt hậu đáng chú ý. Hình ảnh đóng gói có lẽ sẽ ổn nếu bạn không có thiết bị rất chậm. – mattlaabs

0

Hãy thử sử dụng android:cacheColorHint="#00000000" cho chế độ xem danh sách của bạn. Để cải thiện hiệu suất bản vẽ trong khi di chuyển hoạt động, khung công tác Android sẽ sử dụng lại gợi ý màu bộ nhớ cache.

Tham chiếu: developer.android.com bài viết.

+0

Ý của bạn là # 000000 – strange

+0

@ sắp xếp thêm 00 có nghĩa là kênh alpha, vì vậy nó sẽ trong suốt –

+0

để sử dụng nó không có thay đổi về hiệu suất. vẫn còn listview di chuyển chậm hơn. –

15

Sau khi tối ưu hóa phương thức getView() của tôi để sử dụng một chủ sở hữu và tái sử dụng convertView nếu nó không phải là null, listview của tôi vẫn còn khá lag. Sau đó, tôi đã thử

listView.setScrollingCacheEnabled(false); 

và giải quyết nó cùng một lúc.

Hy vọng điều này sẽ giúp ai đó.

+0

điều này đã giúp tôi. Cảm ơn! –

+0

Tôi đã nhìn thấy nó nhiều lần khi gõ gợi ý. Nhưng không bao giờ biết mục đích. +1 –

1

Mất một lúc! Tôi đã thử mọi thứ. Vô hiệu hóa bộ nhớ cache cuộn, viewHolder, cacheColorHint ... nhưng không có gì làm việc!

Sau khi tìm kiếm nhiều giờ, tôi đã tìm thấy gốc rễ của tất cả điều ác!

Trong themes.xml của tôi, tôi đã có một hình nền rộng:

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

Sau khi loại bỏ tất cả mọi thứ beackground là bơ trơn tru.

Tôi hy vọng điều này sẽ giúp ai đó!

6

Tôi vừa phát hiện ra điều này và tôi muốn chia sẻ với các bạn.

Tôi đã thử TẤT CẢ các giải pháp được cung cấp nhưng không có gì hiệu quả. Điều gì gây ra sự cố là độ dài của văn bản tôi đang cho ăn một trong các chế độ xem TextView của mình bởi vì tôi đang sử dụng

mTextView.SetText(theLongString) 

trong bộ điều hợp của mình trong phương pháp getView. Bây giờ mà tôi co Chuỗi tôi, listview là RẤT mịn :)

+0

tôi cũng gặp vấn đề tương tự !! nhưng tại sao!? (cảm ơn rất nhiều vì giải pháp đáng yêu của bạn !!!: D) – strings95

1

Để cải thiện hiệu suất của listview sử dụng cả hai hoặc bất kỳ một trong hai - (thực hiện đơn giản)

  • ViewHolder
  • AsyncTask (một riêng biệt thread)

Nếu bạn có danh sách dài vừa, tôi khuyên bạn nên ViewHolder nếu không cho danh sách lớn (như trong trường hợp trình phát nhạc), tôi khuyên bạn nên sử dụng ViewHolder cùng với AsyncTask. Chìa khóa để làm trơn trượt việc cuộn ListView là giảm mức tiêu thụ bộ nhớ càng nhiều càng tốt.

Để triển khai ViewHolder, thật đơn giản. Chỉ cần tạo một lớp tĩnh trong Bộ điều hợp tùy chỉnh chứa tất cả các khung nhìn mà bạn tìm thấy thông qua findViewById. Vì vậy, đây là cách nó nên nhìn -

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

Sau đó, lần sau bạn cần phải findViewById bất kỳ của những quan điểm, chỉ cần tham khảo các ViewHolder như this-

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

này được kiểm tra mã và lấy từ một trong những dự án của tôi. Tuy nhiên, nguồn ban đầu là ở đây - http://developer.android.com/training/improving-layouts/smooth-scrolling.html

Danh sách trở nên mượt mà hơn bằng cách sử dụng ViewHolder. Sử dụng AsyncTask phức tạp hơn một chút, nhưng hãy kiểm tra liên kết nếu bạn muốn triển khai AsyncTask cùng với ViewHolder để có trải nghiệm cuộn mượt mà hơn. Chúc may mắn!

0

này có thể giúp một số một

Nếu bạn có một hình ảnh trong danh sách của bạn Item, bạn phải nhớ để giảm chất lượng của hình ảnh đó. Nó nhanh hơn để tải trong một vài Kb hơn một vài megabyte.

này đã giúp tôi

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

tôi đã cùng một vấn đề trước khi tôi đã sử dụng bố trí khác nhau như LinearLayout, RelativeLayout, CardView như phụ huynh của con khác nhau trong cùng một mục danh sách xem. Tôi đã giải quyết vấn đề đó bằng cách thay đổi tất cả các khung nhìn bên trong RelativeLayout.

Sử dụng RelativeLayout làm bố cục chính và con của nó có thể tăng tốc độ tải từng mục. Vì vậy, di chuyển sẽ được mịn màng.

<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

Bạn có thể sử dụng listview.setScrollingCacheEnabled (false) .Khi di chuyển khu vực giữ ứng dụng listview sau đó ném Out Of Memory (OOM) giải pháp exception.My đang làm việc cho tôi.

Các vấn đề liên quan