Không cần bỏ kết quả của findViewById?


152

Gần đây tôi thấy rằng AndroidStudio nhắc tôi xóa một số lớp. Tôi nhớ rằng thời xưa, chúng ta phải bỏ kết quả của findViewById, nhưng bây giờ không cần thiết.

Kết quả của findViewById vẫn là View, vì vậy tôi muốn biết lý do tại sao chúng ta không cần phải phân lớp?

Tôi không thể tìm thấy bất kỳ tài liệu nào được đề cập rằng, bất cứ ai cũng có thể tìm thấy bất kỳ tài liệu nào?


7
bởi vì bây giờ là nó <T extends View> T findViewById(int id)?
Selvin

bạn cần truyền trong trường hợp có bất kỳ thao tác nào không có trong lớp View, như trong trường hợp ImageView, Nếu bạn muốn sử dụng setImageResource, thì bạn cần truyền findViewById với ImageView
Gagan Deep

Nhưng tôi cảm thấy hơi bất tiện khi biết loại biến trong nháy mắt nếu loại bỏ việc đúc "dư thừa".
Trái cây

Câu trả lời:


235

Bắt đầu với API 26, findViewByIdsử dụng suy luận cho loại trả về của nó, do đó bạn không còn phải truyền.

Định nghĩa cũ:

View findViewById(int id)

Định nghĩa mới:

<T extends View> T findViewById(int id)

Vì vậy, nếu bạn compileSdkít nhất 26 tuổi, điều đó có nghĩa là bạn có thể sử dụng điều này :)


Cảm ơn, và một câu hỏi khác. Tôi không thể tìm thấy nguồn cho sdk26 trong trình quản lý sdk, vậy tôi có thể tìm định nghĩa mới này ở đâu?
Eric Zhao

17
Nếu chúng tôi loại bỏ các diễn viên, ứng dụng của chúng tôi vẫn có thể chạy trên các thiết bị thấp hơn, phải không?
dùng1032613

17
@ user1032613: Có, các ứng dụng vẫn có thể hoạt động trên các thiết bị thấp hơn mà không gặp vấn đề gì.
Alireza Noorali

1
Điều này sẽ ném một ngoại lệ nếu nó là loại sai?
fobbymaster

1
Như trong nếu xem trong tập tin bố trí là một loại khác nhau? Vâng, tất nhiên, nó vẫn sẽ là một ClassCastException.
Eduard B.

13

Theo bài viết này :

Hàm sau đây dựa trên suy luận kiểu tự động chung của Java để loại bỏ nhu cầu truyền thủ công:

protected <T extends View> T findViewById(@IdRes int id) {
    return (T) getRootView().findViewById(id);
}

11

Trong các phiên bản cũ hơn:

AutoCompleteTextView name = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);

Từ Android Studio 3.0 với SDK 26:

AutoCompleteTextView name = findViewById(R.id.autoCompleteTextView);

16
Điều này không cung cấp câu trả lời của câu hỏi.
Wijay Sharma

1

Android Studio nhắc nhở xóa truyền, nếu bạn sử dụng các thuộc tính phổ biến từ lớp View , như khả năng hiển thị hoặc một số phương thức phổ biến, như onClick ()

Ví dụ:

((ImageView) findViewById(R.id.image_car)).setVisibility(View.VISIBLE);

Trong trường hợp này, bạn có thể chỉ cần viết:

findViewById(R.id.image_car).setVisibility(View.VISIBLE);

2
bạn vẫn phải khai báo kiểu, bạn sẽ phải viết: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito

Android Studio nhắc nhở chúng tôi xóa bỏ phân phối rõ ràng vì nó đã thay đổi khi triển khai suy luận kiểu tự động chung của Java - nó không liên quan gì đến phương thức bạn đang sử dụng.
zeroDivider

1

Android 0, dọn dẹp truyền

Một trong những điều mà google công bố trong IO 2017 là một thứ gọi là 'bỏ đi' :). Nhà phát triển Android không phải thực hiện truyền thủ công cho findViewById (). Ví dụ, cách cũ để có được chế độ xem văn bản bằng findViewById () sẽ giống như thế này.

TextView txtDesc = (TextView) findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

Trong khi cách mới sẽ như thế này

TextView txtDesc = findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

Đó là một thay đổi đơn giản. Nhưng đối với một lập trình viên dày dạn kinh nghiệm, một mã sạch như thế này có thể khiến bạn rất hài lòng và nó giúp ích cho tâm trạng mã hóa của bạn :)

Để có thể làm điều này, bạn chỉ cần đặt phiên bản sdk được biên dịch dự án của bạn thành phiên bản 26 trong ứng dụng build.gradle của bạn.

Bạn vẫn có thể nhắm mục tiêu phiên bản sdk trước đó, vì vậy đó là một thay đổi không xâm phạm.

Bây giờ vấn đề thực sự, làm thế nào để bạn làm sạch mã cũ sử dụng đúc tất cả thời gian này. Đặc biệt là khi bạn có hàng trăm tệp hoạt động. Bạn có thể làm nó bằng tay, hoặc có thể thuê một thực tập viên để làm điều đó. Nhưng may mắn cho tất cả những người thực tập, studio android đã sẵn sàng giúp chúng tôi thực hiện điều này.

Khi bạn đặt dấu mũ của bạn (hoặc nhấp vào quá trình truyền dự phòng), studio sẽ gợi ý 2 tùy chọn để xử lý việc truyền dự phòng.

Đầu tiên, nó sẽ đề nghị loại bỏ cast thừa đó hoặc bạn có thể chọn dọn sạch mã. Nó sẽ loại bỏ tất cả các cast thừa cho tập tin đó. Điều này là tốt hơn, nhưng chúng tôi muốn nhiều hơn nữa. Chúng tôi không muốn mở từng tệp và làm sạch từng cái một.

Một trong những điều làm cho ý tưởng của IntelliJ trở nên đặc biệt là một tính năng được gọi là hành động có chủ đích. Tất cả bạn phải làm là đẩy ctrl + shift + A và sau đó gõ sạch. Và chọn Code Clean up action, và chọn toàn bộ phạm vi dự án. Với một vài bước đơn giản, mã của bạn sẽ sạch hơn rất nhiều.

Một điểm quan trọng là bạn làm điều này với một số hệ thống phiên bản mã. Bằng cách này, bạn có thể so sánh các thay đổi được thực hiện bằng hành động có chủ ý và hoàn nguyên bất kỳ tệp nào bạn muốn.

Sao chép từ bài gốc:

https://medium.com/@abangkis/android-0-clean-up-casting-c30acec56cef


1
câu hỏi là why, không phải how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider

"Tất cả những gì bạn phải làm là đẩy ctrl + shift + A và sau đó gõ sạch". "Loại sạch" có nghĩa là gì? Nếu bạn bắt đầu nhập vào thời điểm đó, bạn sẽ xóa toàn bộ tệp
Rabbi tàng hình

0

Trong mã nguồn của ViewGroup, có một nhóm các đối số trả về. Vì vậy, không cần phải đúc lại:

@Nullable
public final <T extends View> T findViewById(@IdRes int id) {
    if (id == NO_ID) {
        return null;
    }
    return findViewTraversal(id);
}

@Override
protected <T extends View> T findViewTraversal(@IdRes int id) {
    if (id == mID) {
        return (T) this;  //###### cast to T
    }

    final View[] where = mChildren;
    final int len = mChildrenCount;

    for (int i = 0; i < len; i++) {
        View v = where[i];

        if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
            v = v.findViewById(id);

            if (v != null) {
                return (T) v; //###### cast to T
            }
        }
    }

    return null;
}
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.