อะไรคือเจตนาของเมธอด getItem และ getItemId ในคลาส Android BaseAdapter?


155

ฉันอยากรู้เกี่ยวกับวัตถุประสงค์ของวิธีการgetItemและgetItemIdใน Class Adapter ใน Android SDK

จากคำอธิบายดูเหมือนว่าgetItemควรส่งคืนข้อมูลพื้นฐาน ดังนั้นถ้าฉันมีชื่อ["cat","dog","red"]และฉันสร้างอะแดปเตอร์aโดยใช้นั้นแล้วa.getItem(1)ควรกลับ "สุนัข" ถูกต้อง? สิ่งที่ควรa.getItemId(1)กลับมา?

หากคุณใช้วิธีการเหล่านี้ในทางปฏิบัติคุณสามารถยกตัวอย่างได้หรือไม่?


16
+1 คำถามที่ยอดเยี่ยม ฉันต้องการชี้ให้เห็นว่าgetItemId()ในArrayAdapter()เสมอกลับมา-1พร้อมกับassert false : "TODO"; return -1;
rds

คำตอบ:


86

ฉันเห็นวิธีการเหล่านี้เป็นวิธีที่สะอาดกว่าในการเข้าถึงข้อมูลรายการของฉัน แทนโดยตรงของการเข้าถึงวัตถุอะแดปเตอร์ของฉันผ่านทางบางอย่างเช่นฉันก็สามารถเรียกเช่นอะแดปเตอร์myListData.get(position)adapter.get(position)

getItemIdเดียวกันจะไปสำหรับ โดยปกติฉันจะใช้วิธีนี้เมื่อฉันต้องการที่จะดำเนินการบางอย่างขึ้นอยู่กับ ID ที่ไม่ซ้ำกันของวัตถุในรายการ สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อทำงานกับฐานข้อมูล ที่ส่งคืนidอาจเป็นการอ้างอิงถึงวัตถุในฐานข้อมูลซึ่งฉันสามารถดำเนินการที่แตกต่างกันใน (update / delete / etc)

ดังนั้นแทนที่จะเข้าถึง ID จากวัตถุข้อมูลดิบอย่างที่myListData.get(position).getId()คุณสามารถadapter.getItemId(position)ใช้ได้

ตัวอย่างหนึ่งของการที่ฉันรู้สึกเหมือนฉันจำเป็นต้องใช้วิธีการเหล่านี้อยู่ในโครงการโดยใช้SeparatedListViewAdapter อะแดปเตอร์นี้สามารถมีอะแดปเตอร์หลายประเภทแต่ละตัวแทนข้อมูลที่เป็นประเภทที่แตกต่างกัน (โดยทั่วไป) เมื่อโทรgetItem(position)บนSeparatedListViewAdapterวัตถุที่ส่งกลับอาจจะแตกต่างกันขึ้นอยู่กับที่ "ส่วนตำแหน่ง" คือการที่คุณส่ง

ตัวอย่างเช่นหากคุณมี 2 ส่วนในรายการของคุณ (ผลไม้และขนม): หากคุณใช้getItem(position)และpositionเกิดขึ้นกับรายการในส่วนผลไม้คุณจะได้รับวัตถุที่แตกต่างจากที่คุณร้องขอgetItem(position)โดยpositionชี้ไปที่รายการในลูกอมมาตรา. จากนั้นคุณอาจคืนค่า ID คงgetItemId(position)ที่ซึ่งแสดงถึงชนิดของข้อมูลที่getItem(position)ส่งคืนหรือใช้instanceofเพื่อกำหนดวัตถุที่คุณมี

นอกเหนือจากที่ฉันพูดไปฉันไม่เคยรู้สึกเหมือนฉันต้องการใช้วิธีการเหล่านี้จริงๆ


7
สำหรับอะแดปเตอร์ที่ไม่เกี่ยวข้องกับ sql, getItemId จะยังคงมีวัตถุประสงค์หรือไม่? ถ้าเป็นเช่นนั้นสิ่งที่ควรกลับ? ตำแหน่ง?
นักพัฒนา android

1
วัตถุประสงค์หรือการใช้วิธีการนั้นขึ้นอยู่กับนักพัฒนาเป็นหลักและไม่ได้เชื่อมโยงกับแอปที่ขับเคลื่อนด้วยฐานข้อมูล ใช้เพื่อประโยชน์ของคุณเพื่อสร้างรหัสที่ชัดเจน / อ่าน / นำมาใช้ใหม่
James

1
ใช่ฉันเดา getView, getCount, getViewTypeCountฯลฯ ถูกนำมาใช้อย่างถูกต้องโดยเฉพาะสำหรับการแสดง UI ListView ของคุณ ฟังก์ชั่นอื่น ๆ เพียงช่วยสร้างการใช้งานฟังก์ชั่นอื่น ๆ เช่นการดำเนินการเพิ่มเติมเมื่อคลิกที่รายการอื่น ๆ แม้ว่าฉันมักจะใช้getItemภายในgetView
เจมส์

1
@NicolasZozol Sure- ปลอดภัยที่จะไม่ใช้getItemIdเพียงแค่ส่งคืน0Lหรือnullและไม่ใช้ที่ใดก็ได้ ฉันไม่เห็นเหตุผลใด ๆ ที่ชัดเจนว่าทำไม UUID จะมีค่ามากกว่าlongคุณค่าของ ID โหมดตัดการเชื่อมต่อ? นั่นอะไร?
James

1
@binnyb: Nicolas หมายความว่าด้วย UUID คุณยังสามารถสร้าง ID เฉพาะที่ถูกต้อง (เช่นบนอุปกรณ์มือถือของคุณ) แม้ว่าจะไม่มีการเชื่อมต่อเครือข่ายก็ตาม
Levite

32

ดูเหมือนว่าคำถามนี้สามารถตอบได้อย่างเรียบง่ายและตรงไปตรงมามากขึ้น ... :-)

พูดง่ายๆก็คือ Android ช่วยให้คุณสามารถแนบlongไปกับListViewรายการใด ๆมันเป็นเรื่องง่าย เมื่อระบบแจ้งให้คุณทราบถึงการเลือกผู้ใช้คุณจะได้รับตัวแปรระบุสามตัวเพื่อบอกสิ่งที่คุณเลือก:

  • อ้างอิงถึงมุมมองของตัวเอง
  • ตำแหน่งตัวเลขในรายการ
  • สิ่งนี้longคุณแนบมากับองค์ประกอบแต่ละอย่าง

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

ความเข้าใจผิดเกี่ยวกับสิ่งที่มันมักจะเกิดจากการประชุมที่เรียบง่าย อะแดปเตอร์ทั้งหมดต้องระบุgetItemId()แม้ว่าจะไม่ได้ใช้การระบุตัวตนที่สามนี้ ดังนั้นตามแบบแผนอะแดปเตอร์เหล่านั้น (รวมถึงตัวอย่างจำนวนมากใน SDK หรือทั่วทั้งเว็บ) เพียงแค่ส่งคืนpositionด้วยเหตุผลเดียว: มันไม่ซ้ำกันเสมอ ถึงกระนั้นหากอะแดปเตอร์กลับpositionมานี่หมายความว่ามันไม่ต้องการใช้คุณสมบัตินี้เลยเนื่องจากpositionรู้จักกันดีอยู่แล้ว

ดังนั้นหากคุณต้องการคืนค่าอื่น ๆ ที่คุณเห็นว่าเหมาะสมให้ทำดังนี้:

@Override
public long getItemId(int position) {
  return data.get(position).Id;
}

1
คำอธิบายที่ดีสำหรับสิ่งนี้getItemId()... จะเกิดอะไรขึ้นเมื่อ / หากวิธีนี้ไม่ถูกแทนที่ในอะแดปเตอร์ที่คุณกำหนดเอง?
dentex

การทำเครื่องหมายนามธรรมในชั้นฐานคุณต้อง นอกจากว่าคุณจะแทนที่สิ่งที่แทนที่อะแดปเตอร์เดิมแน่นอน พยายามทิ้งมันไว้และถ้า Eclipse บ่นคุณก็ต้องทำ :-)
Gábor

ขอบคุณ ฉันมีวิธีนี้เสมอแสดงความคิดเห็นโดยไม่มีคำเตือน ฉันมีCustomAdapter ขยาย ArrayAdapter <CustomListItem>ด้วย getCount (), getItem (... ) และ getView (... ) โดยใช้ "รูปแบบตัวยึด" เพิ่งออกมาจากความอยากรู้อยากเห็น ...
38745

ใช่คุณสามารถทำได้เพราะArrayAdapterขยายBaseAdapterและให้การใช้งานของตัวเองแล้ว
Gábor

และด้วยอาร์เรย์ที่เรียบง่าย แต่ให้พิจารณาอีกกรณีหนึ่งเมื่อคุณต้องการแสดงรายการจากฐานข้อมูล จากนั้นคุณจะขยายBaseAdapterและคุณสามารถใช้ ID แบบยาวนี้เพื่อจัดเก็บคีย์ฐานข้อมูล เมื่อผู้ใช้เลือกบางสิ่งคุณจะได้รับกุญแจสำคัญของบันทึกที่เลือกโดยตรงผ่านอาร์กิวเมนต์ID จากนั้นคุณสามารถโหลดจากฐานข้อมูลได้ทันที ปัญหาเดียวที่คุณต้องใช้ปุ่มตัวเลขเพราะ Android ตัดสินใจเลือกแบบยาวแทนที่จะใช้บางอย่างที่กว้างขึ้น
Gábor

6

getItemIdวิธีการได้รับการออกแบบส่วนใหญ่จะทำงานร่วมกับเคอร์เซอร์ที่ได้รับการสนับสนุนโดยฐานข้อมูล SQLite มันจะคืนค่าฟิลด์ id เคอร์เซอร์พื้นฐานของรายการในตำแหน่งที่ 1

ในกรณีของคุณไม่มี id สำหรับรายการในตำแหน่งที่ 1: ฉันถือว่าการใช้งานของ ArrayAdapter จะส่งกลับค่า -1 หรือ 0

แก้ไข: จริงๆแล้วมันแค่คืนตำแหน่ง: ในกรณี1นี้


2
-1ไม่มีก็จะส่งกลับ นี่คือการดำเนินการassert false : "TODO"; return -1;
RDS

5
สำหรับ Android 4.1.1 จะส่งคืนตำแหน่ง: grepcode.com/file/repository.grepcode.com/java/ext/…
emmby

4

ฉันต้องการพูดถึงว่าหลังจากใช้งานgetItemและgetItemIdคุณสามารถใช้ListView.getItemAtPositionและListView.getItemIdAtPositionเพื่อเข้าถึงข้อมูลของคุณโดยตรงแทนที่จะไปผ่านอะแดปเตอร์ สิ่งนี้อาจมีประโยชน์โดยเฉพาะอย่างยิ่งเมื่อใช้งานฟัง onClick


3
นี่เป็นประโยชน์อย่างยิ่งถ้าคุณมีส่วนหัวใน listview ของคุณและตำแหน่งที่ส่งไปยังตัวจัดการการคลิกถูกปิดโดยหนึ่ง
เอนโทรปี

4

ถ้าคุณใช้getItemIdอย่างถูกต้องมันอาจมีประโยชน์มาก

ตัวอย่าง:

คุณมีรายการอัลบั้ม:

class Album{
     String coverUrl;
     String title;
}

และคุณใช้งานgetItemIdเช่นนี้:

@Override
public long getItemId(int position){
    Album album = mListOfAlbums.get(position);
    return (album.coverUrl + album.title).hashcode();
}

ตอนนี้ไอเท็มไอเท็มของคุณขึ้นอยู่กับค่าของcoverUrlและฟิลด์หัวเรื่องและถ้าคุณเปลี่ยนและเรียกnotifyDataSetChanged()ใช้อะแด็ปเตอร์ของคุณอะแด็ปเตอร์จะเรียกใช้เมธอด getItemId () ของแต่ละองค์ประกอบและอัปเดตเฉพาะรายการที่มีการเปลี่ยนแปลง

นี้จะเป็นประโยชน์มากถ้ากำลังทำบางอย่าง "หนัก" getView()การดำเนินงานในของคุณ

BTW: หากคุณต้องการให้มันใช้งานได้คุณต้องแน่ใจว่าhasStableIds()วิธีการของคุณคืนเป็นเท็จ


นี่เป็นข้อสังเกตที่มีค่าคุณสามารถให้ข้อมูลบางอย่างเพื่อสนับสนุนกลไกการอัพเดตแบบเลือกนี้ได้หรือไม่?
Jaime Agudo

ทำไมต้องhasStableIds()กลับเท็จ? มันดูเหมือนว่าฉันว่าแฮชโค้ดคำนวณจากสายเดียวกันจะกลับค่าเดียวกันทุกครั้งซึ่งเป็นหมายเลขที่มีเสถียรภาพตามเอกสาร
Big McLargeHuge

พิจารณาว่าการใช้ hashCode อาจคืนค่าจริงเป็นสองสาย
htafoya

2

getItemหรือgetItemIdเป็นวิธีการส่วนใหญ่ที่ออกแบบมาเพื่อแนบข้อมูลกับรายการในรายการ ในกรณีที่getItemคุณสามารถส่งวัตถุใด ๆ ที่จะแนบไปกับรายการในรายการ nullโดยปกติคนกลับมา getItemIdเป็นlongค่าที่ไม่ซ้ำใครที่คุณสามารถแนบกับรายการเดียวกันในรายการ คนทั่วไปกลับตำแหน่งในรายการ

การใช้งานคืออะไร เนื่องจากค่าเหล่านี้ถูกผูกไว้กับรายการในรายการคุณสามารถแยกค่าได้เมื่อผู้ใช้คลิกที่รายการ ค่าเหล่านี้สามารถเข้าถึงได้ผ่านAdapterViewวิธีการ

// template class to create list item objects
class MyListItem{
    public String name;
    public long dbId;

    public MyListItem(String name, long dbId){
        this.name = name;
        this.dbId = dbId;
    }
}

///////////////////////////////////////////////////////////

// create ArrayList of MyListItem
ArrayList<MyListItem> myListItems = new ArrayList<MyListItem>(10);

// override BaseAdapter methods
@Override
public Object getItem(int position) {
    // return actual object <MyListItem>
    // which will be available with item in ListView
    return myListItems.get(position);
}

@Override
public long getItemId(int position) {
    // return id of database document object
    return myListItems.get(position).dbId;
}

///////////////////////////////////////////////////////////

// on list item click, get name and database document id
my_list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        // extract item data
        MyListItem selectedItem = (MyListItem)parent.getItemAtPosition(position);      
        System.out.println("Your name is : " + selectedItem.name);

        // extract database ref id
        long dbId = id;

        // or you could also use
        long dbId = parent.getItemIdAtPosition(position);
    }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.