phương thức getView bộ điều hợp listview tùy chỉnh được gọi nhiều lần và không theo thứ tự mạch lạc


162

Tôi có một bộ điều hợp danh sách tùy chỉnh:

class ResultsListAdapter extends ArrayAdapter<RecordItem> {

trong phương thức 'getView' bị ghi đè, tôi thực hiện in để kiểm tra vị trí nào và đó có phải là convertView hay không:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        System.out.println("getView " + position + " " + convertView);

Đầu ra của cái này (khi danh sách được hiển thị lần đầu tiên, chưa có đầu vào của người dùng)

04-11 16:24:05.860: INFO/System.out(681): getView 0 null  
04-11 16:24:29.020: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43d415d8  
04-11 16:25:48.070: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43d415d8  
04-11 16:25:49.110: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43d415d8  
04-11 16:25:49.710: INFO/System.out(681): getView 0 android.widget.RelativeLayout@43d415d8  
04-11 16:25:50.251: INFO/System.out(681): getView 1 null  
04-11 16:26:01.300: INFO/System.out(681): getView 2 null  
04-11 16:26:02.020: INFO/System.out(681): getView 3 null  
04-11 16:28:28.091: INFO/System.out(681): getView 0 null  
04-11 16:37:46.180: INFO/System.out(681): getView 1 android.widget.RelativeLayout@43cff8f0  
04-11 16:37:47.091: INFO/System.out(681): getView 2 android.widget.RelativeLayout@43cff8f0  
04-11 16:37:47.730: INFO/System.out(681): getView 3 android.widget.RelativeLayout@43cff8f0  

AFAIK, mặc dù tôi không thể tìm thấy nó được nêu rõ ràng, getView () chỉ được gọi cho các hàng hiển thị. Vì ứng dụng của tôi bắt đầu với bốn hàng có thể nhìn thấy, ít nhất là các số vị trí quay vòng từ 0-3 có ý nghĩa. Nhưng phần còn lại là một mớ hỗn độn:

  • Tại sao getview được gọi cho mỗi hàng ba lần?
  • Những convertView này đến từ đâu khi tôi chưa cuộn?

Tôi đã làm một chút về nghiên cứu, và không nhận được câu trả lời tốt, tôi đã nhận thấy rằng mọi người đang liên kết vấn đề này với các vấn đề bố trí. Vì vậy, trong trường hợp, đây là cách bố trí có chứa danh sách:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent" 
    android:orientation="vertical" >

    <TextView android:id="@+id/pageDetails"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />

    <ListView android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" 
        android:drawSelectorOnTop="false" />

</LinearLayout>

và cách bố trí của từng hàng riêng lẻ:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="108dp"    
android:padding="4dp">

<ImageView
    android:id="@+id/thumb"        
    android:layout_width="120dp"
    android:layout_height="fill_parent"        
    android:layout_alignParentTop="true"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_marginRight="8dp"        
    android:src="@drawable/loading" />

<TextView  
    android:id="@+id/price"
    android:layout_width="wrap_content"
    android:layout_height="18dp"         
    android:layout_toRightOf="@id/thumb"
    android:layout_alignParentBottom="true"       
    android:singleLine="true" />

<TextView  
    android:id="@+id/date"
    android:layout_width="wrap_content"
    android:layout_height="18dp"         
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true" 
    android:paddingRight="4dp"       
    android:singleLine="true" />

<TextView
    android:id="@+id/title"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="17dp" 
    android:layout_toRightOf="@id/thumb"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:paddingRight="4dp"   
    android:layout_alignWithParentIfMissing="true"
    android:gravity="center" />

</RelativeLayout>

Cảm ơn bạn đã dành thời gian

Câu trả lời:


271

Đây không phải là một vấn đề, hoàn toàn không có gì đảm bảo về thứ tự getView()sẽ được gọi cũng như bao nhiêu lần. Trong trường hợp cụ thể của bạn, bạn đang làm điều tồi tệ nhất có thể với a ListViewbằng cách cho nó a height=wrap_content. Điều này buộc ListViewphải đo một vài đứa trẻ ra khỏi bộ chuyển đổi tại thời điểm bố trí, để biết nó nên lớn như thế nào. Đây là những gì cung cấp ListViewvới những convertViewsgì bạn thấy được chuyển đến getView()ngay cả trước khi bạn cuộn.


10
Tôi không thấy đây là một lý do tốt. Điều đó tốt nếu bạn muốn có thể thay đổi, nhưng hiện tại nó không trả lời tại sao nó lại thực hiện hành vi này?
cdpnet

45
@cdpnet Anh ấy đã nói lý do tại sao nó làm điều đó, ListViewchiều cao của bạn wrap_content, vì vậy nó không chắc chắn về chiều cao của nó vì vậy nó đưa một số trẻ em ra làm người kiểm tra để xem cái gì sẽ phù hợp. Thay đổi ListViewđể fill_parentkiểm tra nhật ký của bạn các cuộc gọi nên được giảm đáng kể.
Blundell

4
Hành vi giữa ListView thời đại 2,3 và 4.x đã thay đổi đáng kể. Điều đáng nói là, khi ListView được thiết kế, các ô / list_items của bạn cần phải là các chế độ xem thuần túy và chúng cần được tối ưu hóa để vẽ nhanh chóng. Theo cuộc thảo luận Google I / O trên ListView, nơi Romain trình bày, getView có thể được gọi chỉ để tối ưu hóa hiển thị chế độ xem và loại bỏ kết quả. Mặc dù theo tôi, đây không phải là nhà phát triển thân thiện như iOS UITableView, nhưng nó là như vậy.
Cameron Lowell Palmer

4
Cảm ơn bạn rất nhiều! Tôi không hiểu tại sao getView () được gọi thường xuyên như vậy. Tôi đã kết hợp quấn_content thành fill_parent và bây giờ ứng dụng của tôi nhanh chóng trở lại :)
Julia Hexen

28
Cần có một cảnh báo khi đặt ListViews thành layout_height = quấn_content vì nó gây ra rất nhiều vấn đề về hiệu năng.
nathanielwolf

53

Hãy thử với match_parenttrên layout_heighttài sản của xem danh sách. Nó sẽ ngăn chặn getView()để được gọi như vậy thường xuyên.


4
Lưu ý rằng Fred T chỉ định layout_height của LIST VIEW ... không phải hàng, đó là những gì tôi đã thử đi thử lại
mblackwell8

8
Lưu ý rằng fill_parentnên được thay thế bằng match_parentAPI cấp 8 trở lên.
Jason Axelson

Tôi nghĩ phương thức getView () sẽ gọi nhiều lần, bằng cách đặt chiều rộng và chiều cao là match_parent cho ListView chỉ giải quyết vấn đề hiệu năng.
Cường Võ

45

Tôi đã thoát khỏi vấn đề này khi tôi thay đổi cả layout_ thong và layout_height thành match_parent (chỉ thay đổi layout_height không giúp được gì).


Lưu ý hữu ích xem ra nếu bạn có các mục lồng nhau. Bạn đã phải thay đổi cái "cao nhất" thành match_parent . Hy vọng nó sẽ giúp được ai đó.


một từ bạn thân "tuyệt vời" nhưng không biết tại sao quấn_content lại tạo ra vấn đề. Điều này đã giải quyết vấn đề của tôi.
Kẻ giết người Android

@AndroidKiller khi bạn sử dụng wrap_content, sau đó ListViewkhông biết có bao nhiêu mục danh sách để trở thành nội dung của Danh sách, đó là lý do tại sao ListViewcố gắng tạo nhiều hàng như nó nghĩ là phù hợp để hiển thị và khi bạn sử dụng fill_parenthoặc match_parent, ListViewnghĩ, ổn, chiều cao của tôi là xvà tôi cần nsố lượng hàng để hiển thị.
Adil Soomro

Cảm ơn bạn rất nhiều ! Với hành vi này, hình ảnh được thay đổi ngẫu nhiên vì nhiều cuộc gọi ... Bây giờ điều này đã ổn kể từ đầu.
Chostakovitch

7

Tôi không thể trả lời câu hỏi "Tại sao" của bạn nhưng tôi chắc chắn có một giải pháp cho vấn đề " lặp lại " các mục ListView khó chịu (nếu bạn có các mục trong bộ sưu tập ur cao hơn chiều cao màn hình).

Như nhiều người ở trên đã đề cập, hãy giữ thuộc tính android: layout_height của thẻ ListVew dưới dạng fill_parent .

Và về hàm getView (), giải pháp là sử dụng một lớp tĩnh có tên là ViewHolder . Kiểm tra này ví dụ . Nó thực hiện thành công nhiệm vụ thêm tất cả các mục trong ur Array hoặc ArrayCollection.

Hy vọng điều này sẽ giúp bạn bè !!

Trân trọng, Siddhant


Hãy thận trọng về việc sử dụng mẫu ViewHolder trong phiên bản đầu của Android (trước ICS) vì nó có thể dẫn bạn đến ngoại lệ MemoryLeak. vui lòng sử dụng nó trong các phiên bản ICS +.
Vahid Ghadiri

@Siddhant cảm ơn tôi đã dành một ngày để tìm ra lý do lặp lại hình ảnh trong tôi GridViewvà thay đổi android:layout_heightandroid:layout_widthkhông hiệu quả với tôi. Nhưng sử dụng ViewHoldernhững hình ảnh cố định lặp đi lặp lại cho tôi, tôi đã trải qua này hướng dẫn android-vogue.blogspot.com/2011/06/...
Nikolay Podolnyy

4

Ques: Tại sao Adaptor gọi getView () manytimes? Trả lời: Khi Listview hiển thị khi cuộn được làm mới chế độ xem của nó với các chế độ xem sắp tới, bộ điều hợp nào cần để có được lượt xem bằng cách gọi getView ().

Ques: Tại sao nó gọi ít hơn nếu chiều rộng và chiều cao của listview được đặt thành fill_parent? Trả lời: Bởi vì bộ lọc có kích thước cố định cho khu vực màn hình cho danh sách, nó sẽ tính toán một lần để hiển thị các chế độ xem trên màn hình.

Hy vọng nó sẽ giải quyết truy vấn của bạn.


Giải thích tuyệt vời. Nhưng match_parent có thể là một lựa chọn tốt hơn.
Fattie

Có @JoeBlow, bạn nên sử dụng match_parent thay vì fill_parent từ API 2.4 / 3.0 trở đi
jitain sharma 17/12/14

4

Tôi đã gặp vấn đề tương tự với trình đơn thả xuống trong AutoCompleteTextView. Tôi đã chiến đấu với vấn đề này trong hai ngày cho đến khi tôi đến đây và bạn chỉ cho tôi giải pháp.

Nếu tôi viết dropDownHeight = "match_parent" thì sự cố đã được khắc phục. Bây giờ vấn đề liên quan đến UI (khi bạn có một mục, danh sách thả xuống quá lớn) nhưng vấn đề về nhiều cuộc gọi (quan trọng hơn nhiều) đã được khắc phục.

Cảm ơn bạn!!


2

"Tại sao getview được gọi cho mỗi hàng ba lần?" Bởi vì getView được gọi khi bạn cuộn trên listview và để nói rõ hơn thì nó được gọi khi vị trí của chế độ xem danh sách của bạn bị thay đổi!


ok, nhưng quan điểm đã không thay đổi. có bốn chế độ xem hàng trên màn hình khi hoạt động bắt đầu và không cuộn hoặc bất kỳ đầu vào nào của người dùng Tôi nhận được ba cuộc gọi getView cho mỗi hàng ...
edzillion

Câu trả lời này là sai. Câu trả lời đúng là việc sử dụng ** quấn_content ** gây ra một số lượng lớn các cuộc gọi đến getView.
Fattie

2

Tôi gặp vấn đề tương tự. Nếu tôi có chiều cao được đặt thành fill_parent, thì tôi nhận được "thường" 2 cuộc gọi mỗi hàng. Nhưng, nếu tôi đặt chiều cao của ListView của mình thành giá trị chính xác, giả sử là 300dp, thì tôi nhận được chính xác một cuộc gọi GetView trên mỗi hàng.

Vì vậy, đối với tôi, cách duy nhất là trước tiên là xác định chiều cao của màn hình, sau đó lập trình chiều cao của listvilew theo giá trị đó theo lập trình. Tôi không thích nó. Tôi hy vọng có một cách tốt hơn.


1
Cảm ơn vì điều đó. Thật buồn cười - câu hỏi này đã không hoạt động trong nhiều tháng nay chỉ để một vài bình luận xuất hiện trong vài tuần qua. Tôi không còn thực hiện dự án này nữa nhưng vì tôi có thời gian nên tôi sẽ thử nó và sau đó quay lại đây để xác nhận. cảm ơn lần nữa
edzillion

tương tự ở đây, tôi nhận được hai cuộc gọi mỗi hàng. Hàng 0,1,2,3 và sau đó 100ms sau 0,1,2,3 khác - đó là một nỗi đau ở mông khi thu thập số liệu thống kê về những hàng được nhìn thấy
Ai đó ở đâu đó vào

2

Đối với tất cả các bạn những người vẫn (Sau khi thiết lập heightcủa ListViewđểmatch_parent ) đang bị mắc kẹt (như tôi đã được):

Bạn cũng phải đặt heightbố trí cha thành match_parent.

Xem ví dụ dưới đây. Đây LinearLayoutlà cha mẹ ở đây:

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/something" />

        <ListView
            android:id="@+id/friendsList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

1

Điều này có thể đến muộn nhưng nếu bạn đang sử dụng layout_weighthãy nhớ luôn đặtlayout_width="0dp"


0

tôi đã thực hiện giải pháp này, có thể không phải là giải pháp tốt nhất, nhưng thực hiện công việc ...

//initialize control string
private String control_input = " ";

sau đó =

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View gridview = convertView;

    // change input_array for the array you use
    if (!control_input.equals(input_array[position])) {
        control_input = input_array[position];

        //do your magic

    } 

    return gridview;
}

hy vọng nó giúp!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.