listview อะแด็ปเตอร์ listview แบบกำหนดเองถูกเรียกหลายครั้งและไม่เรียงลำดับกัน


162

ฉันมีอะแดปเตอร์รายการที่กำหนดเอง:

class ResultsListAdapter extends ArrayAdapter<RecordItem> {

ในเมธอด 'getView' ที่แทนที่ฉันจะพิมพ์เพื่อตรวจสอบตำแหน่งที่อยู่และไม่ว่าจะเป็น convertView หรือไม่:

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

ผลลัพธ์ของสิ่งนี้ (เมื่อรายการถูกแสดงครั้งแรกไม่มีการป้อนข้อมูลของผู้ใช้เป็นยัง)

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 แม้ว่าฉันจะไม่สามารถระบุได้ชัดเจน แต่ getView () จะถูกเรียกเฉพาะแถวที่มองเห็นเท่านั้น เนื่องจากแอปของฉันเริ่มต้นด้วยแถวที่มองเห็นได้สี่แถวเป็นอย่างน้อยตัวเลขตำแหน่งหมุนเวียนจาก 0-3 จึงสมเหตุสมผล แต่ส่วนที่เหลือเป็นระเบียบ:

  • เหตุใด getview จึงถูกเรียกสำหรับแต่ละแถวสามครั้ง
  • ตัวอย่างการแปลงเหล่านี้มาจากไหนเมื่อฉันยังไม่ได้เลื่อน?

ฉันได้ทำการ reseach อีกเล็กน้อยและไม่ได้รับคำตอบที่ดีเลยฉันสังเกตได้ว่าผู้คนกำลังเชื่อมโยงปัญหานี้กับปัญหาการจัดวาง ดังนั้นในกรณีนี้นี่คือเค้าโครงที่มีรายการ:

<?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>

และเค้าโครงของแต่ละแถว:

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

ขอขอบคุณสำหรับเวลาของคุณ

คำตอบ:


271

นี่ไม่ใช่ปัญหาไม่มีการรับประกันอย่างแน่นอนเกี่ยวกับคำสั่งที่getView()จะถูกเรียกหรือไม่กี่ครั้ง โดยเฉพาะในกรณีของคุณคุณจะทำสิ่งที่เลวร้ายที่สุดไปได้ด้วยโดยให้มันเป็นListView height=wrap_contentนี่เป็นการบังคับListViewให้วัดเด็กสองสามคนออกจากอะแดปเตอร์ในเวลาเลย์เอาท์เพื่อให้รู้ว่ามันควรใหญ่ขนาดไหน นี่คือสิ่งที่ให้ListViewกับconvertViewsคุณเห็นผ่านไปgetView()ก่อนที่จะเลื่อน


10
ฉันไม่พบสิ่งนี้เป็นเหตุผลที่ดี ไม่เป็นไรถ้าคุณต้องการที่จะเปลี่ยนแปลง แต่ในปัจจุบันยังไม่ตอบว่าทำไมมันถึงทำแบบนี้
cdpnet

45
@cdpnet เขาบอกว่าทำไมมันถึงทำแบบนั้นคุณListViewมีความสูงwrap_contentดังนั้นจึงไม่แน่ใจว่ามันสูงเท่าไหร่ดังนั้นจึงทำให้เด็กบางคนออกมาเป็นเครื่องทดสอบเพื่อดูว่าจะเหมาะกับอะไรเปลี่ยนของคุณListViewเป็นfill_parentเช็คของคุณแล้ว การโทรควรลดลงอย่างมาก
Blundell

4
ListView ระหว่าง 2.3 และ 4.x ยุคนั้นเปลี่ยนไปอย่างมาก สิ่งที่ต้องทำคือ ListView ได้รับการออกแบบเซลล์ / list_items ของคุณต้องเป็นมุมมองที่บริสุทธิ์และจะต้องปรับให้เหมาะสำหรับการวาดอย่างรวดเร็ว ตามการพูดคุยของ Google I / O ใน ListView ซึ่ง Romain นำเสนอแสดงว่า getView อาจถูกเรียกเพียงเพื่อปรับการเรนเดอร์มุมมองให้เหมาะสมและละทิ้งผลลัพธ์ แม้ว่าในความคิดของฉันมันไม่ได้เป็นมิตรกับนักพัฒนาเท่า iOS UITableView แต่มันเป็นอย่างไร
Cameron Lowell Palmer

4
ขอบคุณมาก! ฉันไม่เข้าใจว่าทำไม getView () จึงถูกเรียกบ่อยครั้ง ฉัน swithced wrap_content เพื่อ fill_parent และตอนนี้แอปของฉันกลับมาเร็วอีกครั้ง :)
Julia Hexen

28
ควรมีคำเตือนเมื่อตั้งค่า ListViews เป็น layout_height = wrap_content เนื่องจากทำให้เกิดปัญหาประสิทธิภาพการทำงานจำนวนมาก
nathanielwolf

53

ลองกับmatch_parentในlayout_heightทรัพย์สินของมุมมองรายการ มันจะป้องกันไม่getView()ให้ถูกเรียกบ่อย


4
โปรดทราบว่า Fred T ระบุ layout_height ของ LIST VIEW ... ไม่ใช่แถวซึ่งเป็นสิ่งที่ฉันลองทำซ้ำแล้วซ้ำอีก
mblackwell8 8

8
โปรดทราบว่าfill_parentควรแทนที่ด้วยmatch_parentสำหรับ API ระดับ 8 ขึ้นไป
Jason Axelson

ฉันคิดว่าวิธี getView () จะเรียกหลายครั้งโดยการตั้งค่าความกว้างและความสูงเป็น match_parent สำหรับ ListView เพียงแก้ปัญหาประสิทธิภาพการทำงาน
Cuong Vo

45

ฉันกำจัดปัญหานี้เมื่อฉันเปลี่ยนทั้ง layout_width และ layout_height เป็นmatch_parent (การเปลี่ยนเฉพาะ layout_height ไม่ได้ช่วย)


หมายเหตุที่เป็นประโยชน์ระวังถ้าคุณมีรายการซ้อนกัน คุณได้มีการเปลี่ยนแปลงอย่างใดอย่างหนึ่ง "สูงสุด" เพื่อmatch_parent หวังว่าจะช่วยใครซักคน


เพื่อนคำเดียว "สุดยอด" แต่ไม่รู้ว่าทำไม wrap_content กำลังสร้างปัญหา นี่เป็นการแก้ไขปัญหาของฉัน
Android Killer

@AndroidKiller เมื่อคุณใช้wrap_contentแล้วListViewไม่ทราบว่ารายการมากจะมีการกลายเป็นเนื้อหารายการของ thats ทำไมListViewพยายามที่จะสร้างเป็นแถวเป็นจำนวนมากที่คิดว่ามีความเหมาะสมที่จะแสดงและเมื่อคุณใช้fill_parentหรือmatch_parent, ListViewคิดว่าไม่เป็นไรความสูงของฉัน คือxและฉันต้องการnจำนวนแถวที่จะแสดง
Adil Soomro

ขอบคุณมาก ! ด้วยภาพพฤติกรรมนี้มีการเปลี่ยนแปลงแบบสุ่มเนื่องจากมีหลายสาย ... ตอนนี้ก็โอเคตั้งแต่เริ่มต้น
Chostakovitch

7

ฉันไม่สามารถตอบคำถาม "Why" ของคุณได้ แต่ฉันมีวิธีแก้ไขปัญหาของปัญหา " ListView items repeating " ที่น่ารำคาญ(หากคุณมีรายการในคอลเลกชัน ur ซึ่งสูงกว่าความสูงของหน้าจอ)

เป็นคนจำนวนมากดังกล่าวข้างต้นได้กล่าวให้หุ่นยนต์: layout_heightทรัพย์สินของListVewแท็กfill_parent

และเกี่ยวกับ getView () ฟังก์ชั่นการแก้ปัญหาคือการใช้ระดับคงที่เรียกว่าViewHolder ตรวจสอบนี้ตัวอย่างเช่น ทำหน้าที่เพิ่มรายการทั้งหมดใน ur Array หรือ ArrayCollection ได้สำเร็จ

หวังว่านี้จะช่วยให้เพื่อน !!

ด้วยความเคารพ Siddhant


ระมัดระวังเกี่ยวกับการใช้รูปแบบ ViewHolder ใน Android เวอร์ชันก่อนหน้า (ICS ก่อน) เพราะอาจนำคุณไปสู่ข้อยกเว้น MemoryLeak อย่าลังเลที่จะใช้มันในเวอร์ชัน ICS +
Vahid Ghadiri

@ Siddhant ขอบคุณฉันใช้เวลาหนึ่งวันเพื่อหาเหตุผลของการทำซ้ำภาพในของฉันGridViewและการเปลี่ยนแปลงandroid:layout_heightและandroid:layout_widthไม่ได้ผลสำหรับฉัน แต่การใช้ViewHolderภาพซ้ำ ๆ แบบคงที่สำหรับฉันฉันผ่านกวดวิชานี้android-vogue.blogspot.com/2011/06/ …
Nikolay Podolnyy

4

คำถาม: ทำไมอะแดปเตอร์เรียกใช้ getView () หลายครั้ง คำตอบ: เนื่องจาก Listview แสดงผลเมื่อเลื่อนเป็นการรีเฟรชมุมมองที่มีมุมมองต่อไปที่จะเกิดขึ้นสำหรับอะแดปเตอร์ที่ต้องการรับมุมมองโดยเรียกใช้ getView ()

เควส: ทำไมมันโทรน้อยลงถ้าตั้งค่าความกว้างและความสูงของ listview เป็น fill_parent? คำตอบ: เนื่องจาก inflator มีขนาดคงที่สำหรับพื้นที่หน้าจอสำหรับรายการจึงคำนวณหนึ่งครั้งสำหรับการแสดงมุมมองลงบนหน้าจอ

หวังว่ามันจะแก้ไขข้อสงสัยของคุณ


คำอธิบายที่ดี แต่match_parentอาจเป็นตัวเลือกที่ดีกว่า
Fattie

ใช่ @JoeBlow ขอแนะนำให้ใช้ match_parent แทน fill_parent จาก API 2.4 / 3.0 เป็นต้นไป
jitain sharma

4

ฉันมีปัญหาเดียวกันกับการเลื่อนลงใน AutoCompleteTextView ฉันต่อสู้กับปัญหาเป็นเวลาสองวันจนกระทั่งฉันมาถึงที่นี่และคุณแสดงวิธีแก้ปัญหาให้ฉัน

ถ้าฉันเขียน dropDownHeight = "match_parent" ปัญหาได้รับการแก้ไข ขณะนี้ปัญหาเกี่ยวข้องกับ UI (เมื่อคุณมีรายการหนึ่งรายการดรอปดาวน์ใหญ่เกินไป) แต่ปัญหาของการโทรหลายครั้ง (สำคัญกว่า) ได้รับการแก้ไข

ขอบคุณ!!


2

"ทำไม getview เรียกแต่ละแถวสามครั้ง" เนื่องจาก getView ถูกเรียกเมื่อคุณเลื่อนไปที่ listview และพูดได้ดีกว่ามันจะถูกเรียกเมื่อตำแหน่งของมุมมองรายการของคุณเปลี่ยนไป!


ตกลง แต่มุมมองยังไม่เปลี่ยน มีสี่มุมมองแถวบนหน้าจอเมื่อกิจกรรมเริ่มต้นและไม่มีการเลื่อนหรือการป้อนข้อมูลของผู้ใช้เลยฉันได้รับการเรียก getView สามครั้งสำหรับแต่ละแถว ...
edzillion

คำตอบนี้ผิด คำตอบที่ถูกต้องคือการใช้ ** wrap_content ** ทำให้การโทรไปยัง getView จำนวนมาก
Fattie

2

ฉันมีปัญหาเดียวกัน หากฉันมีความสูงตั้งไว้ที่ fill_parent ฉันจะได้รับ "ปกติ" 2 สายต่อแถว แต่ถ้าฉันตั้งค่าความสูงของ ListView เป็นค่าที่แน่นอนสมมุติว่า 300dp แล้วฉันจะได้รับการเรียก GetView หนึ่งครั้งต่อแถว

ดังนั้นสำหรับฉันแล้วดูเหมือนว่าวิธีเดียวคือกำหนดความสูงของหน้าจอก่อนจากนั้นตั้งค่าความสูงของ listvilew โดยทางโปรแกรมให้เป็นค่านั้น ฉันไม่ชอบมัน ฉันหวังว่าจะมีวิธีที่ดีกว่า


1
ขอบคุณสำหรับสิ่งนั้น เป็นเรื่องตลก - คำถามนี้ซ่อนตัวอยู่นานหลายเดือนในขณะนี้เพื่อให้มีความคิดเห็นเล็กน้อยปรากฏในช่วงสองสามสัปดาห์ที่ผ่านมา ฉันไม่ได้ทำโครงการนี้อีกต่อไป แต่เนื่องจากฉันมีเวลาฉันจะลองทำและกลับมาที่นี่เพื่อยืนยัน ขอบคุณอีกครั้ง.
edzillion

เหมือนกันที่นี่ฉันได้รับสองสายต่อแถว แถว 0,1,2,3 และจากนั้น 100 มิลลิวินาทีในภายหลังอีก 0,1,2,3 - ซึ่งเป็นความเจ็บปวดในตูดเมื่อรวบรวมสถิติเกี่ยวกับสิ่งที่เห็นแถว
บางคนที่ไหนสักแห่ง

2

สำหรับทุกท่านที่ยังคง (หลังจากการตั้งค่าheightของListViewถึงmatch_parent) ติดอยู่ (เหมือนฉัน):

คุณยังมีการตั้งค่าของรูปแบบการปกครองheightmatch_parent

ดูตัวอย่างด้านล่าง The LinearLayoutparent คือที่นี่:

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


0

ฉันทำโซลูชันนี้อาจไม่ใช่วิธีที่ดีที่สุด แต่ใช้งานได้ ...

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

จากนั้น =

@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;
}

หวังว่ามันจะช่วย!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.