2009-11-07 39 views
83

Tôi có một res/layout/main.xml bao gồm cả những yếu tố này và những người khác:findViewById() trả về null cho thành phần tùy chỉnh trong cách bố trí XML, không cho các thành phần khác

<some.package.MyCustomView android:id="@+id/foo" (some other params) /> 
<TextView android:id="@+id/boring" (some other params) /> 

Trong onCreate Hoạt động của tôi, tôi làm điều này:

setContentView(R.layout.main); 
TextView boring = (TextView) findViewById(R.id.boring); 
// ...find other elements... 
MyCustomView foo = (MyCustomView) findViewById(R.id.foo); 
if (foo == null) { Log.d(TAG, "epic fail"); } 

Các thành phần khác được tìm thấy thành công, nhưng foo trở về null. MyCustomView có một hàm tạo MyCustomView(Context c, AttributeSet a) và một Log.d(...) ở cuối hàm tạo đó xuất hiện thành công trong logcat ngay trước "lỗi sử thi".

Tại sao là foo không?

Trả lời

163

Vì trong hàm dựng, tôi có super(context) thay vì super(context, attrs).

Làm cho tinh thần, nếu bạn không chuyển vào các thuộc tính, chẳng hạn như id, thì chế độ xem sẽ không có id và do đó không thể tìm thấy được bằng id đó. :-)

+1

Luôn luôn tốt đẹp để có thể trả lời câu hỏi của riêng bạn :) Hãy chắc chắn đánh dấu bạn là câu trả lời được chấp nhận. – MattC

+0

Thật vậy. Sẽ làm như vậy khi SO cho phép tôi ("Bạn có thể chấp nhận câu trả lời của riêng bạn trong 2 ngày.") –

+4

Ngoài ra, không nên các dòng như '(MyCustomView) foo = findViewById (R.id.foo);' được 'MyCustomView foo = (MyCustomView) findViewById (R.id.foo); '? –

1

Đối với tôi, sự cố đã được giải quyết khi tôi thêm thư mục res vào Nguồn trong Đường dẫn xây dựng Java trong Cài đặt dự án.

11

Cùng một vấn đề, nhưng giải pháp khác nhau: Tôi không gọi

setContentView(R.layout.main) 

TRƯỚC Tôi cố gắng để tìm ra quan điểm như đã nêu here

+1

có cùng một vấn đề và cùng một giải pháp – sami

+0

Tôi nghĩ đây là giải pháp nếu bạn nhận được phần tử ở chế độ xem khác thay vì chế độ xem có liên quan hiện tại. – StarCub

18

tôi đã cùng một vấn đề. Sai lầm của tôi là: Tôi đã viết

 LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     View layout=inflater.inflate(R.layout.dlg_show_info, null); 
     alertDlgShowInfo.setView(layout); 
     TableRow trowDesc=(TableRow)findViewById(R.id.trowDesc); 

và khi tôi sử dụng inflater để "tải" chế độ xem từ tệp XML, dòng cuối cùng sai. Để giải quyết nó, tôi phải viết:

TableRow trowDesc=(TableRow)layout.findViewById(R.id.trowDesc); 

Tôi đã viết giải pháp của mình, trong trường hợp ai đó có cùng vấn đề.

+0

Dude, bạn là một genious. Đó là giải pháp duy nhất giúp tôi vượt qua tất cả những thứ tôi đọc trên S.O. –

+0

CÓ BẠN! hàng giờ tôi đã thử mọi thứ. THANKS :) – user690936

+0

Đây cũng là vấn đề đối với tôi. Wow, những gì một ... Tôi đã đưa tôi ngày để tìm ra điều này một mình. Cảm ơn bạn! – poshaughnessy

18

Dường như có nhiều lý do khác nhau. Tôi vừa mới sử dụng "Clean ..." trong Eclipse để giải quyết một vấn đề tương tự. (FindViewByID đã làm việc trước đây và vì một lý do nào đó bắt đầu trả về giá trị rỗng.)

+1

dường như, vấn đề cơ bản là các ID R.java bằng cách nào đó bị hỏng hoặc có thể không được cập nhật. Tôi đã nhận thấy điều này không chỉ với các ID, mà còn trong các trường hợp khác, ví dụ: chuỗi sai hiển thị trong một TextView vv. Thực sự không biết tại sao điều này xảy ra, mặc dù. – jellyfish

+0

Điều này đã khiến tôi đau buồn quá lâu - một sự sạch sẽ đã thực sự khắc phục nó cho tôi. –

+0

Cảm ơn!Một sạch đơn giản thực sự là những gì tôi cần. –

0

Vấn đề của tôi là lỗi đánh máy. Tôi đã viết android.id (dấu chấm) thay vì android:id. : P

Rõ ràng không có kiểm tra cú pháp trong xml thành phần tùy chỉnh của tôi. :(

0

Đã cùng một vấn đề.

tôi đã bố trí với vài trẻ em. Từ constructor của một chúng tôi đã cố gắng để có được tài liệu tham khảo (bằng cách sử dụng context.findViewById) cho con khác. Nó không làm việc vì đứa con thứ hai được xác định hơn nữa trong cách bố trí

tôi đã giải quyết nó như thế này:.

setContentView(R.layout.main); 
MyView first = findViewById(R.layout.first_child); 
first.setSecondView(findViewById(R.layout.second_child)); 

nó sẽ làm việc cũng như nếu thứ tự của trẻ em là đối diện, nhưng tôi đoán nó thường nên được thực hiện như ở trên.

+1

Nói chung, bạn không nên sử dụng 'findViewById' trong hàm tạo của' Chế độ xem', nhưng thay vì đặt mã khởi tạo trong 'OnFinishInflate'? –

0

Phương thức findViewById() đôi khi trả về null khi gốc của bố cục không có thuộc tính android:id. Trình hướng dẫn Eclipse để tạo tệp xml bố cục không tự động tạo thuộc tính android:id cho phần tử gốc.

2

Trong trường hợp của tôi findViewById được trở về null vì giao diện tùy chỉnh của tôi nhìn một cái gì đó như thế này trong XML chính:

 <com.gerfmarquez.seekbar.VerticalSeekBar 
      android:id="@+id/verticalSeekBar" 
      android:layout_width="wrap_content" 
      android:layout_height="fill_parent" 
      /> 

và tôi phát hiện ra rằng khi tôi thêm xmlns nhét nó làm việc như thế này:

 <com.gerfmarquez.seekbar.VerticalSeekBar 
      xmlns:android="http://schemas.android.com/apk/res/android" 
      android:id="@+id/verticalSeekBar" 
      android:layout_width="wrap_content" 
      android:layout_height="fill_parent" 
      /> 
0

trong trường hợp của tôi xem là trong các phụ huynh không theo quan điểm tôi đã cố gắng để gọi nó trong Vì vậy, trong giao diện nhỏ, tôi đã phải gọi:.

RelativeLayout relLayout = (RelativeLayout) this.getParent(); 
View view1 = relLayout.findViewById(R.id.id_relative_layout_search); 
2

Hãy chắc chắn rằng cuộc gọi tuyên bố setContentView(R.layout.main) trước tuyên bố findViewById(...);

0

Tùy chọn 'sạch' hoạt động đối với tôi.

Trong trường hợp của tôi, nguyên nhân gốc là mã nguồn nằm trên chia sẻ mạng và máy trạm và máy chủ tệp của tôi không được đồng bộ chính xác và đã trôi dạt 5 giây. Dấu thời gian trên các tệp được tạo bởi Eclipse là trong quá khứ (vì chúng được gán bởi máy chủ tệp) w.r.t. đồng hồ của máy trạm, làm cho Eclipse giải quyết các phụ thuộc giữa các tệp nguồn được tạo và không chính xác. Trong trường hợp này, một 'sạch' xuất hiện để làm việc, bởi vì nó buộc một xây dựng lại hoàn toàn thay vì một xây dựng gia tăng phụ thuộc vào dấu thời gian sai.

Khi tôi đã sửa cài đặt NTP trên máy trạm của mình, sự cố không bao giờ xảy ra nữa. Nếu không có các thiết lập NTP thích hợp, nó sẽ xảy ra vài giờ một lần, khi các đồng hồ trôi nhanh.

+0

Nên thêm điều này vào nhận xét của [answer] (http://stackoverflow.com/a/5420286/1050058) trên –

1

Tôi chạy vào cùng một vấn đề một khi trở lại khi tôi đã thêm một tùy chỉnh Xem qua XML layout và sau đó đã cố gắng để gắn một callback ở đâu đó trong ứng dụng ...

Tôi tạo ra một giao diện tùy chỉnh và bổ sung nó vào "layout_main.xml" của tôi "

public class MUIComponent extends SurfaceView implements SurfaceHolder.Callback { 
    public MUIComponent (Context context, AttributeSet attrs) { 
     super (context, attrs); 
    } 
    // .. 
} 

Và trong hoạt động chính, tôi muốn đính kèm một số cuộc gọi lại và tham khảo các thành phần giao diện người dùng từ XML.

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // ... 

     MUIInitializer muiInit = new MUIInitializer(); 
     muiInit.setupCallbacks(this); 
     muiInit.intializeFields(this); 
    }  
} 

Các initilizer đã không làm bất cứ điều gì lạ mắt nhưng bất kỳ thay đổi nó cố gắng thực hiện với giao diện tùy chỉnh (MUIComponent) hoặc phi tùy chỉnh phần UI khác chỉ đơn giản là không được xuất hiện trong ứng dụng.

public class MUIInitializer { 

    // ... 

    public void setupCallbacks (Activity mainAct) { 


     // This does NOT work properly 
     // - The object instance returned is technically an instance of my "MUICompnent" view 
     // but it is a *different* instance than the instance created and shown in the UI screen 
     // - Callbacks never get triggered, changes don't appear on UI, etc. 
     MUIComponent badInst = (MUIComponent) mainAct.findViewById(R.id.MUIComponent_TESTSURF); 


     // ... 
     // This works properly 

     LayoutInflater inflater = (LayoutInflater) mainAct.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     View inflatedLayout = inflater.inflate (R.layout.activity_main, null); 

     MUIComponent goodInst = (MUIComponent) inflatedLayout.findViewById(R.id.MUIComponent_TESTSURF); 


     // Add callbacks 
     // ... 
    } 

} 

Sự khác biệt giữa "badInst" và "goodInst" là:

  • badInst sử dụng findViewByID của Hoạt động
  • goodInst thổi phồng cách bố trí và sử dụng cách bố trí thổi phồng để làm tra cứu
+0

Nhận thấy Vincent có cùng giải pháp ... và câu trả lời ngắn hơn ... +1 thay vào đó :) – DevByStarlight

3

Nếu bạn có nhiều phiên bản bố cục (tùy thuộc vào mật độ màn hình, phiên bản SDK), hãy đảm bảo rằng tất cả các phiên bản đó đều bao gồm phần tử bạn đang tìm kiếm.

0

Để thêm một sai lầm không đáng kể các câu trả lời để tìm cho ra:

Kiểm tra xem bạn đang thực sự chỉnh sửa các tập tin XML bố trí đúng ...

0

tôi đã có cùng một vấn đề, vì tôi quên để cập nhật id chế độ xem trong tất cả thư mục bố cục của tôi.

17

Tôi có cùng một vấn đề bởi vì trong chế độ xem tùy chỉnh của tôi, tôi đã ghi đè hàm tạo nhưng được gọi là siêu đối số không có dấu cộng. Đó là bản sao dán)

phiên bản constructor trước đây của tôi:

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

Bây giờ tôi có:

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

Và đó hoạt động!

+0

Tương tự vấn đề ở đây. Ngẫu nhiên đó là một lỗi dán bản sao cho tôi quá. – KurtCobain

+0

Điều tương tự đã xảy ra với tôi. Câu trả lời đúng nhất trên Stackoverflow. Khi thêm AttributeSet attrs trở lại, mọi thứ đều ổn. – spikeyang

1

Điều này xảy ra với tôi với một thành phần tùy chỉnh cho Wear, nhưng là một lời khuyên chung chung. Nếu bạn đang sử dụng Stub (chẳng hạn như tôi đang sử dụng WatchViewStub), bạn không thể chỉ cần thực hiện cuộc gọi đến findViewById() ở bất kỳ đâu. Mọi thứ bên trong cuống phải được thổi phồng trước, điều này không chỉ xảy ra sau setContentView(). Vì vậy, bạn nên viết một cái gì đó như thế này để chờ đợi cho điều đó xảy ra:

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_wear); 
    final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); 
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { 
     @Override 
     public void onLayoutInflated(WatchViewStub stub) { 
      myCustomViewInst = (MyCustomView) findViewById(R.id.my_custom_view); 
      ... 
Các vấn đề liên quan