Mục đích của các phương thức getItem và getItemId trong lớp BaseAd CHƯƠNG của Android là gì?


155

Tôi tò mò về mục đích của các phương thức getItemgetItemIdtrong Bộ điều hợp lớp trong SDK Android.

Từ mô tả, có vẻ như getItemsẽ trả về dữ liệu cơ bản. Vì vậy, nếu tôi có một loạt các tên ["cat","dog","red"]và tôi tạo một bộ chuyển đổi abằng cách sử dụng nó, thì a.getItem(1)nên trả lại "con chó", đúng không? Nên a.getItemId(1)trả lại cái gì?

Nếu bạn đã sử dụng các phương pháp này trong thực tế, bạn có thể cung cấp một ví dụ không?


16
+1 Câu hỏi xuất sắc. Tôi muốn chỉ ra rằng getItemId()ArrayAdapter()luôn trả về -1vớiassert false : "TODO"; return -1;
RDS

Câu trả lời:


86

Tôi thấy các phương pháp này là một cách tiếp cận sạch hơn để truy cập dữ liệu của danh sách của tôi. Thay vì truy cập trực tiếp vào đối tượng bộ điều hợp của tôi thông qua một cái gì đó như myListData.get(position)tôi chỉ có thể gọi bộ điều hợp như thế adapter.get(position).

Cũng vậy getItemId. Thông thường tôi sẽ sử dụng phương thức này khi tôi muốn thực thi một số tác vụ dựa trên ID duy nhất của một đối tượng trong danh sách. Điều này đặc biệt hữu ích khi làm việc với cơ sở dữ liệu. Trả về idcó thể là một tham chiếu đến một đối tượng trong cơ sở dữ liệu mà sau đó tôi có thể thực hiện các hoạt động khác nhau trên (cập nhật / xóa / vv).

Vì vậy, thay vì truy cập ID từ đối tượng dữ liệu thô như myListData.get(position).getId()bạn có thể sử dụng adapter.getItemId(position).

Một ví dụ về nơi mà tôi cảm thấy cần sử dụng các phương thức này là trong một dự án sử dụng Tách biệtListViewAd CHƯƠNG . Bộ điều hợp này có thể chứa nhiều loại bộ điều hợp khác nhau, mỗi loại đại diện cho dữ liệu của một loại khác nhau (thông thường). Khi gọi getItem(position)trên SeparatedListViewAdapter, đối tượng trả về có thể khác nhau tùy thuộc vào "phần" vị trí mà bạn gửi nó.

Ví dụ, nếu bạn có 2 phần trong danh sách của bạn (trái cây và kẹo): Nếu bạn sử dụng getItem(position)positionđược đề cập tới một mục trong trái phần, bạn sẽ nhận được một đối tượng khác nhau hơn nếu bạn yêu cầu getItem(position)với positiontrỏ đến một mục trong kẹo phần. Sau đó, bạn có thể trả về một số loại giá trị ID không đổi trong getItemId(position)đó đại diện cho loại dữ liệu nào getItem(position)được trả về hoặc sử dụng instanceofđể xác định đối tượng bạn có.

Khác với những gì tôi đã đề cập, tôi chưa bao giờ cảm thấy mình thực sự cần sử dụng các phương pháp này


7
Đối với các bộ điều hợp không liên quan đến sql, getItemId vẫn có mục đích chứ? Nếu vậy, những gì cần được trả lại? Chức vụ?
nhà phát triển Android

1
mục đích hoặc việc sử dụng phương pháp chủ yếu phụ thuộc vào nhà phát triển và không bị ràng buộc với ứng dụng điều khiển cơ sở dữ liệu. sử dụng nó để lợi thế của bạn để tạo mã rõ ràng / có thể đọc / tái sử dụng.
James

1
Vâng tôi đoán. getView, getCount, getViewTypeCount, Vv được sử dụng đặc biệt cho thấy đúng UI listview của bạn. các chức năng khác chỉ đơn giản là giúp tạo ra các chức năng khác như thực hiện các hành động tiếp theo khi nhấp vào một mục, v.v. mặc dù tôi thường sử dụng getItembên tronggetView
james

1
@NicolasZozol Chắc chắn - không an toàn khi thực hiện getItemId, chỉ cần trả lại 0Lhoặc nullkhông sử dụng nó ở bất cứ đâu. Tôi không thấy bất kỳ lý do rõ ràng nào tại sao một UUID sẽ có giá trị hơn chỉ một số longgiá trị cho ID. Chế độ ngắt kết nối? Cái gì vậy
James

1
@binnyb: Nicolas có nghĩa là với UUID, vẫn có thể tạo ID duy nhất hợp lệ (ví dụ: trên thiết bị di động của bạn), ngay cả khi không có kết nối mạng.
Levite

32

Chà, có vẻ như câu hỏi này có thể được trả lời theo cách đơn giản và dễ hiểu hơn ... :-)

Nói một cách đơn giản, Android cho phép bạn đính kèm longbất kỳ ListViewmục nào , thật đơn giản. Khi hệ thống thông báo cho bạn về lựa chọn người dùng, bạn sẽ nhận được ba biến xác định để cho bạn biết những gì đã được chọn:

  • một tham chiếu đến chính quan điểm,
  • vị trí số của nó trong danh sách,
  • cái này longbạn gắn liền với các yếu tố cá nhân.

Tùy thuộc vào bạn để quyết định cái nào trong ba cái này là dễ nhất để bạn xử lý trong trường hợp cụ thể của bạn nhưng bạn có cả ba để lựa chọn mọi lúc. Hãy nghĩ về điều này longnhư một thẻ tự động được gắn vào vật phẩm, chỉ có điều nó thậm chí còn đơn giản và dễ đọc hơn.

Sự hiểu lầm về những gì nó thường bắt nguồn từ một quy ước đơn giản. Tất cả các bộ điều hợp phải cung cấp getItemId()ngay cả khi họ không thực sự sử dụng nhận dạng thứ ba này. Vì vậy, theo quy ước, những bộ điều hợp đó (bao gồm nhiều mẫu trong SDK hoặc trên toàn bộ web) chỉ đơn giản trở lại positionvì một lý do duy nhất: nó luôn luôn là duy nhất. Tuy nhiên, nếu một bộ chuyển đổi trả về position, điều này thực sự có nghĩa là nó hoàn toàn không muốn sử dụng tính năng này,positiondù sao cũng đã biết.

Vì vậy, nếu bạn cần trả về bất kỳ giá trị nào khác mà bạn thấy phù hợp, vui lòng làm như vậy:

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

1
Giải thích hay cho điều này getItemId()... Điều gì xảy ra khi / nếu phương thức này không bị ghi đè trong bộ điều hợp tùy chỉnh của bạn?
vết lõm

Được đánh dấu trừu tượng trong lớp cơ sở, bạn phải. Tất nhiên trừ khi bạn ghi đè lên một cái gì đó ghi đè lên bộ điều hợp gốc, tất nhiên. Cố gắng bỏ nó ra, và nếu Eclipse phàn nàn thì bạn phải làm. :-)
Gábor

Cảm ơn. Tôi đã luôn có phương pháp này nhận xét mà không có cảnh báo. Tôi có một CustomAd CHƯƠNG mở rộng ArrayAd CHƯƠNG <CustomListItem> với getCount (), getItem (...) và getView (...), bằng cách sử dụng "mẫu giữ". Chỉ tò mò thôi ...
dentex

Yep, bạn có thể làm điều đó bởi vì ArrayAdapter kéo dài BaseAdapter và đã cung cấp thực hiện riêng của mình.
Gábor

Và với một mảng đơn giản, không sao cả. Nhưng chỉ cần xem xét một trường hợp khác, ví dụ khi bạn muốn hiển thị các mục từ cơ sở dữ liệu. Sau đó , bạn có thể sẽ mở rộng BaseAd CHƯƠNG và bạn có thể sử dụng ID dài này để lưu trữ khóa cơ sở dữ liệu. Khi người dùng chọn một cái gì đó, bạn sẽ trực tiếp lấy lại khóa của bản ghi đã chọn thông qua đối số id . Sau đó, bạn có thể tải nó từ cơ sở dữ liệu ngay lập tức. Vấn đề duy nhất là bạn phải sử dụng các phím số vì Android quyết định dài thay vì một cái gì đó rộng hơn.
Gábor

6

Các getItemIdphương pháp được thiết kế chủ yếu để làm việc với Cursors được hỗ trợ bởi cơ sở dữ liệu SQLite. Nó sẽ trả về trường id của con trỏ bên dưới cho mục ở vị trí 1.

Trong trường hợp của bạn, không có id cho mục ở vị trí 1: Tôi giả sử việc triển khai của ArrayAd CHƯƠNG chỉ trả về -1 hoặc 0.

EDIT: thực sự, nó chỉ trả về vị trí: trong trường hợp này 1.


2
Không, nó trở lại -1. Đây là cách thực hiệnassert false : "TODO"; return -1;
rds

5
Kể từ Android 4.1.1, nó trả về vị trí: grepcode.com/file/reposective.grepcode.com/java/ext/ gợi
emmby

4

Tôi muốn đề cập rằng sau khi triển khai getItemgetItemIdbạn có thể sử dụng ListView.getItemAtP vị tríListView.getItemIdAtP vị trí để truy cập trực tiếp dữ liệu của bạn, thay vì đi qua bộ điều hợp. Điều này có thể đặc biệt hữu ích khi triển khai trình nghe onClick.


3
Điều này thực sự rất hữu ích nếu bạn có một tiêu đề trong danh sách của bạn và các vị trí được chuyển đến trình xử lý nhấp chuột bị tắt bởi một
entropy

4

Nếu bạn thực hiện getItemIdđúng thì nó có thể rất hữu ích.

Thí dụ :

Bạn có một danh sách các album:

class Album{
     String coverUrl;
     String title;
}

Và bạn thực hiện getItemIdnhư thế này:

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

Bây giờ id mục của bạn phụ thuộc vào các giá trị của trường coverUrltiêu đề và nếu bạn thay đổi và gọi notifyDataSetChanged()bộ điều hợp của mình, thì bộ điều hợp sẽ gọi phương thức getItemId () của từng thành phần và chỉ cập nhật các mục mà id đã thay đổi.

Điều này rất hữu ích nếu đang thực hiện một số thao tác "nặng" trong của bạn getView().

BTW: nếu bạn muốn nó hoạt động, bạn cần chắc chắn rằng hasStableIds()phương thức của bạn trả về false;


Đây là một quan sát có giá trị, bạn có thể cung cấp một số dữ liệu để sao lưu cơ chế cập nhật chọn lọc này không?
Jaime Agudo

Tại sao nên hasStableIds()trả lại sai? Dường như với tôi, mã băm được tính toán từ cùng một chuỗi sẽ trả về cùng một giá trị mỗi lần, đó là một ID ổn định theo các tài liệu .
Big McLargeHuge

xem xét rằng việc sử dụng hashCode có thể trả về đúng cho hai Chuỗi
htafoya

1

getItemhoặc getItemIdlà một vài phương thức chủ yếu được thiết kế để đính kèm dữ liệu với các mục trong danh sách. Trong trường hợp getItem, bạn có thể vượt qua bất kỳ đối tượng nào sẽ đính kèm vào mục trong danh sách. Bình thường mọi người trở về null. getItemIdlà bất kỳ longgiá trị duy nhất nào bạn có thể đính kèm với cùng một mục trong danh sách. Mọi người thường trả lại vị trí trong danh sách.

Việc sử dụng là gì. Chà, vì những giá trị này được ràng buộc với mục trong danh sách, bạn có thể trích xuất chúng khi người dùng nhấp vào mục đó. Những giá trị này có thể truy cập thông qua AdapterViewcác phương thức.

// 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);
    }
});
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.