findViewByID trả về null


251

Trước hết: có, tôi đọc tất cả các chủ đề khác về chủ đề này. Và không chỉ những người từ trang web này ... (bạn thấy đấy, tôi hơi thất vọng)

Hầu hết trong số họ đi kèm với lời khuyên để sử dụng android:idthay vì chỉ idtrong tệp XML. Tôi đã làm.

Từ những người khác, tôi học được, điều đó View.findViewByIdlàm việc khác hơn Activity.findViewById. Tôi cũng xử lý việc đó.

Trong tôi location_layout.xml, tôi sử dụng:

<FrameLayout .... >
    <some.package.MyCustomView ... />

    <LinearLayout ... >
        <TextView ...
            android:id="@+id/txtLat" />
        ...
    </LinearLayout>
</FrameLayout>

Trong hoạt động của tôi, tôi làm:

...
setContentView( R.layout.location_layout );

và trong lớp xem tùy chỉnh của tôi:

... 
TextView tv = (TextView) findViewById( R.id.txtLat );

Mà trả về null. Làm điều này, Hoạt động của tôi hoạt động tốt. Vì vậy, có lẽ đó là vì sự Activity.findViewByIdView.findViewByIdsự khác biệt. Vì vậy, tôi đã lưu trữ bối cảnh được chuyển đến nhà xây dựng chế độ xem hải quan tại địa phương và thử:

...
TextView tv = (TextView) ((Activity) context).findViewById( R.id.txtLat );

Mà cũng trở về null.

Sau đó, tôi đã thay đổi chế độ xem tùy chỉnh của mình để mở rộng ViewGroupthay vào đó Viewvà thay đổi location_layout.xmlđể cho phép TextViewtrở thành con trực tiếp của chế độ xem tùy chỉnh của tôi, để chế độ View.findViewByIdnày hoạt động như được cho là đúng. Bất ngờ: nó không giải quyết được gì.

Vì vậy, những gì tôi đang làm sai?

Tôi sẽ đánh giá cao bất kỳ ý kiến.


6
Điều này có thể xảy ra nếu dự án bị hỏng quá. Tôi đã sửa nó bằng cách làm sạch dự án
Pacerier

1
vượt qua chế độ xem bối cảnh sai cảm ơn
izzy

1
@Pacerier cảm ơn bạn. đã giải quyết vấn đề của tôi. Tôi bắt đầu ghét lập trình Android ở Xamarin)
Artiom

@Pacerier "Dự án sạch" cũng giải quyết vấn đề của tôi. Có vẻ như Dropbox đã làm hỏng dự án.
Kohki Mametani

Câu trả lời:


271

trả về null

Có thể bởi vì bạn đang gọi nó quá sớm. Đợi đến khi onFinishInflate(). Dưới đây là một dự án mẫu cho thấy một tùy chỉnh Viewtruy cập nội dung của nó.


67
CHÚA ƠI! Không thể tin rằng tôi dành nhiều ngày cho một cái gì đó tầm thường. Tôi đã di chuyển setContentView () phía trên lệnh findViewById () và điều đó không lừa được anh ta. cảm ơn!
đặc vụ

2
@CommonsWare đó là dự án chính xác? Tôi không thấy onFinishInflate ở bất cứ đâu trong github.com/commonsguy/cw-advandroid/tree/master/Animation/
trộm

1
@likejiujitsu: Nó có thể đã có từ năm 2010. Tôi đã cập nhật liên kết đến một dự án mới hơn onFinishInflate().
CommonsWare

3
Tôi có setContentView được gọi trước findViewById và nó vẫn là null. Tôi đang tham khảo một EditText
Warge

1
Luôn liên kết với các cam kết GitHub cố định (ví dụ: github.com/commonsguy/cw-omnibus/tree/, ) và không bao giờ xóa repos hoặc rebase ;-)
Ciro Santilli 冠状 病 六四 法轮功 法轮功 14/2/2016

145

Có thể, bạn đang gọi findViewByIdtrước khi gọi setContentView? Nếu đó là trường hợp, hãy thử gọi findViewById SAU cuộc gọisetContentView


1
Một lỗi dễ dàng như vậy, nhưng thật không may, đây là những gì tôi đã làm. Trình gỡ lỗi không được sử dụng vì nó cho biết lỗi là do mục đích mới của tôi không nằm trong hoạt động mới thực tế mà tôi đang gọi. Cảm ơn!
edude05

6
Trên thực tế tôi đã gặp lỗi này vì tôi đang gọi setContentView chỉ vào chế độ xem sai ... thật không may trình biên dịch không bắt được loại lỗi này.
HeatfanJohn

Có, tôi đã xóa setContentView do nhầm lẫn và không hiểu tại sao chương trình của tôi bắt đầu bị hỏng.
Ronen Festinger

100

Đảm bảo bạn không có nhiều phiên bản bố cục cho các mật độ màn hình khác nhau. Tôi đã gặp vấn đề này một lần khi thêm id mới vào bố cục hiện có nhưng quên cập nhật phiên bản hdpi. Nếu bạn quên cập nhật tất cả các phiên bản của tệp bố cục, nó sẽ hoạt động với một số mật độ màn hình nhưng không phải là các phiên bản khác.


8
CẢM ƠN! Điều đó là vậy đó. (Trong trường hợp của tôi, tôi có nhiều phiên bản cho các phiên bản Android khác nhau). Tôi quên nó mọi lúc mặc dù tôi đặt một bình luận khổng lồ trên đầu và cuối của mỗi tệp bố cục. Tôi muốn trình biên dịch sẽ tạo ra một lỗi hoặc cảnh báo lớn nếu điều này xảy ra.
tiktak

Đinh ding ding, cảm ơn bạn rất nhiều! Đã uốn cong bộ não của tôi về lol này
Zach

21

FindViewById có thể là null nếu bạn gọi siêu xây dựng sai trong chế độ xem tùy chỉnh. Thẻ ID là một phần của attrs, vì vậy nếu bạn bỏ qua attrs, bạn xóa ID.

Điều này sẽ sai

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context);
}

Chính xác

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context,attrs);
}

1
Cảm ơn bạn rất nhiều ạ! Vì vậy, tôi bất cẩn, tôi thậm chí nghi ngờ rằng có điều gì đó không ổn với IDE của tôi. Thật may mắn khi gặp câu trả lời của bạn.
Hiệu

Tôi đã phạm sai lầm này khi tôi tạo chế độ xem tùy chỉnh của mình. Cảm ơn bạn, repkap11.
Andrew F.

15

Trong trường hợp của tôi, tôi đã có 2 hoạt động trong dự án của mình, main.xmlmain2.xml. Ngay từ đầu, main2là một bản sao của main, và tất cả mọi thứ hoạt động tốt, cho đến khi tôi thêm mới TextViewđể main2, do đó R.id.textview1trở thành có sẵn cho phần còn lại của ứng dụng. Sau đó, tôi đã cố gắng tìm nạp nó bằng cách gọi tiêu chuẩn:

TextView tv = (TextView) findViewById( R.id.textview1 );

và nó luôn luôn là null. Hóa ra, trong onCreateconstructor tôi đã bắt đầu không phải main2, mà là cái khác. Tôi đã có:

setContentView(R.layout.main);

thay vì

setContentView(R.layout.main2);

Tôi nhận thấy điều này sau khi tôi đến đây, trên trang web.


14

Bên cạnh các nguyên nhân cổ điển, được đề cập ở nơi khác:

  • Hãy chắc chắn rằng bạn đã gọi setContentView()trướcfindViewById()
  • Đảm bảo rằng idbạn muốn có trong chế độ xem hoặc bố cục bạn đã cung cấp chosetContentView()
  • Hãy chắc chắn rằng idkhông vô tình trùng lặp trong các bố cục khác nhau

Có một cái tôi đã tìm thấy cho các chế độ xem tùy chỉnh trong bố cục tiêu chuẩn, đi ngược lại với tài liệu:

Về lý thuyết, bạn có thể tạo chế độ xem tùy chỉnh và thêm nó vào bố cục ( xem tại đây ). Tuy nhiên, tôi đã thấy rằng trong các tình huống như vậy, đôi khi idthuộc tính hoạt động cho tất cả các chế độ xem trong bố cục ngoại trừ các chế độ tùy chỉnh. Giải pháp tôi sử dụng là:

  1. Thay thế mỗi chế độ xem tùy chỉnh bằng một FrameLayoutthuộc tính bố cục giống như bạn muốn có chế độ xem tùy chỉnh. Cho nó một cái thích hợp id, nói frame_for_custom_view.
  2. Trong onCreate:

    setContentView(R.layout.my_layout);
    FrameView fv = findViewById(R.id.frame_for_custom_layout);
    MyCustomView cv = new MyCustomView(context);
    fv.addView(cv);

    trong đó đặt chế độ xem tùy chỉnh trong khung.


Điều này giúp tôi: "Đảm bảo rằng id bạn muốn nằm trong chế độ xem hoặc bố cục bạn đã cung cấp cho setContentView ()". Làm gì khi đó là một cuộc phỏng vấn? Đã thử nhận chế độ xem của phụ huynh sau đó thực hiện ParentView.findById () nhưng nó vẫn trả về null
NaturalBornCamper

@naturalborncamper nếu bạn đăng một câu hỏi riêng với mã ví dụ tôi sẽ xem nó.
Neil Townsend

Cảm ơn Neil, tôi đã đăng bài và ai đó đã chỉ ra một cách tốt hơn để làm điều này, mặc dù nó không hoạt động chính xác như thế nào nên tôi phải sử dụng một chiến lược khác: stackoverflow.com/questions/47955376/
trộm

9
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }

6

Một câu trả lời cho những người sử dụng ExpandableListView và chạy vào câu hỏi này dựa trên tiêu đề của nó.

Tôi đã gặp lỗi này khi cố gắng làm việc với TextViews trong các chế độ xem con và nhóm của tôi như là một phần của việc triển khai ExpandableListView.

Bạn có thể sử dụng một cái gì đó như sau trong các triển khai phương thức getChildView () và getgroupView () của bạn.

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_layout, null);
        }

Tôi tìm thấy điều này ở đây .


5

Tôi khá mới với Android / Eclipse, do nhầm lẫn, tôi đã thêm công cụ UI vào activity_main.xmlthay vì fragment_main.xml. Mất vài giờ để tìm ra điều đó ...


5

FWIW, tôi không thấy có ai giải quyết vấn đề này theo cách tương tự như tôi cần. Không có khiếu nại tại thời gian biên dịch, nhưng tôi đã nhận được một chế độ xem null trong thời gian chạy và gọi mọi thứ theo đúng thứ tự. Đó là, findViewById () sau setContentView (). Vấn đề hóa ra là chế độ xem của tôi được định nghĩa trong content_main.xml, nhưng trong Activity_main.xml của tôi, tôi thiếu một tuyên bố này:

<include layout="@layout/content_main" />

Khi tôi thêm nó vào Activity_main.xml, không còn NullPulum nữa.


Vấn đề với việc sao chép dán một mảnh là bạn đôi khi quên thay đổi một số thứ ... là bố cục chính xác để làm tăng một trong số chúng. Cảm ơn!
Pablo Quemé

3

Tôi có vấn đề này như nhau. Tôi đã sử dụng thư viện của bên thứ ba cho phép bạn ghi đè bộ điều hợp của họ cho GridView và để chỉ định bố cục của riêng bạn cho mỗi ô GridView.

Cuối cùng tôi cũng nhận ra chuyện gì đang xảy ra. Eclipse vẫn đang sử dụng tệp xml bố trí của thư viện cho từng ô trong GridView, mặc dù nó không cho thấy điều này. Trong bộ điều hợp tùy chỉnh của tôi, nó chỉ ra rằng nó đang sử dụng tài nguyên xml từ dự án của riêng tôi mặc dù trong thời gian chạy, nó không như vậy.

Vì vậy, những gì tôi đã làm là đảm bảo bố cục xml và id tùy chỉnh của tôi khác với những người vẫn ngồi trong thư viện, dọn dẹp dự án và sau đó nó bắt đầu đọc các bố cục tùy chỉnh chính xác trong dự án của tôi.

Nói tóm lại, hãy cẩn thận nếu bạn ghi đè bộ điều hợp của thư viện bên thứ ba và chỉ định xml bố cục của riêng bạn để bộ điều hợp sử dụng. Nếu bố cục bên trong dự án của bạn có cùng tên tệp trong thư viện, bạn có thể gặp phải một lỗi thực sự khó tìm!


3

Trong trường hợp cụ thể của tôi, tôi đã cố gắng thêm chân trang vào ListView. Cuộc gọi sau đây trong onCreate () đã trả về null.

TextView footerView = (TextView) placesListView.findViewById(R.id.footer);

Thay đổi điều này để làm tăng chế độ xem chân trang thay vì tìm nó bằng ID đã giải quyết vấn đề này.

View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer_view, null, false);

2

Trong trường hợp của tôi, tôi đã sử dụng ExpandableListView và tôi đã thiết lập android:transcriptMode="normal". Điều này đã khiến một vài đứa trẻ trong nhóm có thể mở rộng biến mất và tôi đã từng có ngoại lệ NULL khi tôi sử dụng cuộn danh sách.


2

Đối với tôi, tôi có hai bố cục xml cho cùng một hoạt động - một ở chế độ dọc và một ở chế độ ngang. Tất nhiên tôi đã thay đổi id của một đối tượng trong xml ngang nhưng đã quên thực hiện thay đổi tương tự trong phiên bản dọc. Đảm bảo rằng nếu bạn thay đổi một cái bạn làm tương tự với xml khác hoặc bạn sẽ không gặp lỗi cho đến khi bạn chạy / gỡ lỗi và nó không thể tìm thấy id bạn không thay đổi. Ôi những lỗi lầm ngu ngốc, tại sao anh phải trừng phạt em như vậy?


2

Đặt nội dung hoạt động từ tài nguyên bố cục. tức là., setContentView(R.layout.basicXml);


2

Ngoài các giải pháp trên, bạn đảm bảo rằng
tools:context=".TakeMultipleImages" bố cục trong cùng một giá trị trong tệp mainfest.xml:
android:name=".TakeMultipleImages"cho cùng một phần tử hoạt động. nó xảy ra khi sử dụng bản sao và dán để tạo hoạt động mới


2

Tôi có cùng một vấn đề, nhưng tôi nghĩ nó đáng để chia sẻ với các bạn. Nếu bạn phải tìmViewById trong bố cục tùy chỉnh, ví dụ:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

bạn không thể có được khung nhìn trong constructor. Bạn nên gọi findViewById sau khi lượt xem tăng cao. Đây là một phương pháp bạn có thể ghi đèonFinishInflate


2

Chỉ muốn ném trường hợp cụ thể của tôi vào đây. Có thể giúp ai đó xuống dòng.

Tôi đã sử dụng chỉ thị trong Android UI XML của mình như thế này:

Quan điểm của phụ huynh:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:visibility="gone" />

Chế độ xem con (retry_button):

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/retry"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">

.findViewById (R.id.retry) sẽ luôn trả về null. Nhưng, nếu tôi chuyển ID từ chế độ xem con sang thẻ bao gồm, nó bắt đầu hoạt động.

Đã sửa lỗi cha mẹ:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:id="@+id/retry"
        android:visibility="gone" />

Con cố định:

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">

2

Trường hợp của tôi là không giống như trên, không có giải pháp làm việc. Tôi cho rằng quan điểm của tôi quá sâu vào hệ thống phân cấp bố cục. Tôi đã di chuyển nó lên một cấp và nó không còn trống nữa.


Tôi có cùng một vấn đề, cũng có thể tìm thấy một cấp độ cao hơn .. điều đó khá khó chịu và tôi muốn biết tại sao nó lại xảy ra vì tôi không thể làm thực đơn của mình như tôi muốn
NaturalBornCamper

Phân cấp bố cục sâu cũng là mô hình chống, hầu như luôn luôn có một giải pháp sạch hơn. Bạn đang nói về menu tràn trong thanh công cụ, hoặc ngăn kéo điều hướng?
Deividas Strioga

Ngăn kéo điều hướng, tôi thực sự đã đăng một câu hỏi khác, ngoại trừ việc thêm một mục menu trong một nhóm không hoạt động, chỉ cần thêm nó vào cuối tất cả các mục: stackoverflow.com/questions/47955376/
Thẻ

1

Trong trường hợp của tôi, tôi đã tăng bố cục nhưng các khung nhìn con đang trả về null. Ban đầu tôi có cái này:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_history);

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) findViewById(R.id.pbListviewFooter);
    tvText = (TextView) findViewById(R.id.tvListviewFooter);
    ...
}

Tuy nhiên, khi tôi thay đổi nó thành như sau thì nó hoạt động:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_history);

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) footerView.findViewById(R.id.pbListviewFooter);
    tvText = (TextView) footerView.findViewById(R.id.tvListviewFooter);
    ...
}

Điều quan trọng là tham chiếu cụ thể bố cục đã bị thổi phồng để có được các khung nhìn con. Đó là, để thêm footerView:

  • chân trang Xem .findViewById ...

0

Theo kinh nghiệm của tôi, dường như điều này cũng có thể xảy ra khi mã của bạn được gọi sau OnDestroyView (khi đoạn nằm ở ngăn sau.) Nếu bạn đang cập nhật giao diện người dùng trên đầu vào từ BroadCastReceiver, bạn nên kiểm tra xem đây có phải là trường hợp không .


0

LẠM PHÁT HAY KHÔNG !! (có chứa id)

Trong trường hợp của tôi, findViewById () trả về null, vì bố cục phần tử được viết, không bị thổi phồng ...

Ví dụ. Fragment_layout.xml

<ListView
android:id="@+id/listview">

findViewById (R.id.listview) trả về null, vì tôi chưa thực hiện Inflater.inflate (R.layout.fragment_layout, ..., ...); trước nó.

Hy vọng câu trả lời này sẽ giúp một số bạn.



0

findViewById cũng có thể trả về null nếu bạn ở trong Fragment. Như được mô tả ở đây: findViewById trong Fragment

Bạn nên gọi getView () để trả về Chế độ xem cấp cao nhất bên trong một Đoạn. Sau đó, bạn có thể tìm thấy các mục bố trí (nút, xem văn bản, v.v.)


0

Tôi đã thử tất cả những thứ trên không có gì hiệu quả .. vì vậy tôi phải làm cho ImageView của mình tĩnhpublic static ImageView texture; và sau đó texture = (ImageView) findViewById(R.id.texture_back);, tôi không nghĩ rằng đó là một cách tiếp cận tốt nhưng điều này thực sự hiệu quả với trường hợp của tôi :)


xin lỗi, tôi nghĩ rằng chế độ xem tĩnh là ý tưởng tồi
vuhung3990

0

Trong trường hợp của tôi, findViewById trả về null khi tôi chuyển cuộc gọi từ đối tượng cha sang đối tượng bộ điều hợp được khởi tạo bởi cha mẹ. Sau khi thử các thủ thuật được liệt kê ở đây mà không thành công, tôi đã di chuyển findViewById trở lại đối tượng cha và truyền kết quả dưới dạng tham số trong quá trình khởi tạo đối tượng bộ điều hợp. Ví dụ, tôi đã làm điều này trong đối tượng cha mẹ:

 Spinner hdSpinner = (Spinner)view.findViewById(R.id.accountsSpinner);

Sau đó, tôi đã chuyển hdSpinner làm tham số trong khi tạo đối tượng bộ điều hợp:

  mTransactionAdapter = new TransactionAdapter(getActivity(),
        R.layout.transactions_list_item, null, from, to, 0, hdSpinner);

0

Nó bị sập đối với tôi vì một trong các trường trong id hoạt động của tôi khớp với id trong một hoạt động khác. Tôi đã sửa nó bằng cách đưa ra một id duy nhất.

Trong id trường mật khẩu loginActivity.xml của tôi là "mật khẩu". Trong hoạt động đăng ký của mình, tôi chỉ sửa nó bằng cách cho id r_password, sau đó nó trả về không đối tượng null:

password = (EditText)findViewById(R.id.r_password);

0

Tôi đã phải đối mặt với một vấn đề tương tự khi tôi đang cố gắng thực hiện một chế độ xem tùy chỉnh cho một ListView .

Tôi đã giải quyết nó đơn giản bằng cách làm điều này:

public View getView(int i, View view, ViewGroup viewGroup) {

    // Gets the inflater
    LayoutInflater inflater = LayoutInflater.from(this.contexto);

    // Inflates the layout
    ConstraintLayout cl2 = (ConstraintLayout) 
    inflater.inflate(R.layout.custom_list_view, viewGroup, false);

    //Insted of calling just findViewById, I call de cl2.findViewById method. cl2 is the layout I have just inflated. 
     TextView tv1 = (TextView)cl2.findViewById(cl2);

0

Các cách để gỡ lỗi và tìm ra vấn đề:

  • Nhận xét tất cả findViewById trong hoạt động của bạn.
  • Nhận xét mọi thứ trừ onCreate và setContentView
  • Chạy dự án và xem nếu bất kỳ bố trí được thiết lập

Trong trường hợp của tôi, tôi đã sử dụng Activity_main.xml trong cả mô-đun ứng dụng và mô-đun thư viện của mình. Vì vậy, khi tôi thực hiện các bước trên, thay vì bố cục mà tôi thiết kế trong thư viện, bố cục bên trong mô-đun ứng dụng đã bị thổi phồng.

Vì vậy, tôi đã thay đổi tên tệp Activity_main.xml thành Activity_main_lib.xml.

Vì vậy, hãy chắc chắn rằng bạn không có bất kỳ tên bố cục trùng lặp nào trong toàn bộ dự án của bạn .

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.