findViewById ()는 다른 구성 요소가 아닌 레이아웃 XML의 사용자 정의 구성 요소에 대해 null을 반환합니다.


91

나는 res/layout/main.xml다음 요소와 다른 요소를 포함하고 있습니다.

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

내 활동의 onCreate에서 다음을 수행합니다.

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"); }

다른 요소는 성공적으로 발견되었지만 foonull로 돌아옵니다. MyCustomView는 생성자가 MyCustomView(Context c, AttributeSet a)와 Log.d(...)그 생성자의 말에 그냥 "서사시 실패"전에 로그 캣에서 성공적으로 나타납니다.

왜 foonull입니까?

답변:


182

생성자에서 super(context)대신 super(context, attrs).

ID와 같은 속성을 전달하지 않으면 뷰에 ID가 없으므로 해당 ID를 사용하여 찾을 수 없습니다. :-)


1
항상 자신의 질문에 답할 수 있다는 것이 좋습니다. :) 귀하의 질문도 허용 된 답변으로 표시해야합니다.
— MattC

과연. SO가 나에게 허용하면 그렇게 할 것입니다 ( "2 일 안에 자신의 답변을 수락 할 수 있습니다.")
— Chris Boyle

4
또한, 당신은 (MyCustomView) foo = findViewById(R.id.foo);될 것 같은 대사를해야하지 MyCustomView foo = (MyCustomView) findViewById(R.id.foo);않습니까?
— Jeremy Logan

3
같은 문제가 있었는데, 제 경우에는 setContentView ()를 잊어 버렸습니다 .. XD
— Tom Brito

vogella.com에서 이러한 작업을 수행하는 좋은 예가 있습니다. vogella.com/articles/AndroidCustomViews/article.html
— Wolkenjaeger 2013

27

내 사용자 정의보기에서 생성자를 재정의했지만 attrs paramete를 사용하여 super contructor를 호출했기 때문에 동일한 문제가 있습니다. 그것은 복사 붙여 넣기입니다)

내 이전 생성자 버전 :

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

지금 나 한테있어:

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

그리고 작동합니다!


여기에도 같은 문제가 있습니다. 덧붙여서 그것은 나에게도 복사 붙여 넣기 오류였습니다.
— KurtCobain

나에게도 같은 일이 일어났습니다. Stackoverflow에서 가장 정답입니다. AttributeSet 속성을 다시 추가하면 모든 것이 정상입니다.
— spikeyang

나는 우리 모두가 사용자 지정보기와 같은 튜토리얼을보고 추측)이 오류가 나에게 무의미 디버깅의 0,5h했다 ...
— KrwawyKefir

이것은 나에게도 효과적이었습니다! 나는 이것을 꽤 오랫동안 싸웠다. 감사!
— us_david

18

나는 같은 문제가 있었다. 내 실수는 다음과 같습니다.

        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);

인플레이터를 사용하여 XML 파일에서 뷰를 "로드"할 때 마지막 줄이 잘못되었습니다. 이를 해결하기 위해 다음과 같이 작성해야했습니다.

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

누군가 같은 문제가있는 경우를 대비하여 솔루션을 작성했습니다.


야, 당신은 천재입니다. 그것은 내가 SO에서 읽은 수많은 것들 중에서 나를 위해 일한 유일한 해결책이었습니다
— IgorGanapolsky

이것은 나에게도 문제였습니다. 와우,이 얼마나 .. 이걸 알아내는 데 며칠이 걸렸을 텐데. 감사합니다!
— poshaughnessy

18

여러 가지 이유가있는 것 같습니다. 비슷한 문제를 해결하기 위해 Eclipse에서 "Clean ..."을 사용했습니다. (FindViewByID는 이전에 작동했으며 어떤 이유로 인해 null을 반환하기 시작했습니다.)


1
분명히 근본적인 문제는 R.java ID가 어떻게 든 손상되거나 업데이트되지 않을 수 있다는 것입니다. 나는 ID뿐만 아니라 다른 경우에도 이것을 알아 차렸다. 예를 들어 TextView 등에 잘못된 문자열이 표시된다. 그래도 왜 이런 일이 발생하는지는 모르겠다.
— jellyfish

이것은 나에게 너무 오랫동안 슬픔을주고 있었다. 깨끗한 것이 나를 위해 실제로 그것을 고쳤다.
— Nicholas MT Elliott

1
실제로 정리. 와우, 짜증나!
— Tim Büthe 2011 년

11

같은 문제이지만 다른 해결책 : 전화하지 않았습니다.

setContentView(R.layout.main)

여기에 언급 된보기를 찾기 전에


현재 관련 뷰 대신 다른 뷰에 요소를 얻는다면 이것이 해결책이라고 생각합니다.
— StarCub 2012

4

여러 레이아웃 버전 (화면 밀도, SDK 버전에 따라 다름)이있는 경우 모든 레이아웃에 찾고있는 요소가 포함되어 있는지 확인하십시오.


2

내 경우에는 내 사용자 정의보기가 기본 XML에서 다음과 같이 보였기 때문에 findViewById가 null을 반환했습니다.

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

xmlns를 추가했을 때 다음과 같이 작동한다는 것을 알았습니다.

        <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" 
            />

2

setContentView(R.layout.main)명령문 이 statement 전에 호출 되는지 확인하십시오 findViewById(...).


1

나를 위해 프로젝트 설정에서 Java 빌드 경로의 소스에 res 폴더를 추가하면 문제가 해결되었습니다.


1

레이아웃 XML을 통해 사용자 지정보기를 추가 한 다음 응용 프로그램의 다른 위치에 콜백을 첨부하려고 할 때 같은 문제가 발생했습니다.

사용자 정의보기를 작성하여 "layout_main.xml"에 추가했습니다.

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

그리고 메인 액티비티에서 콜백을 첨부하고 XML에서 UI 요소에 대한 참조를 얻고 싶었습니다.

public class MainActivity extends Activity {

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

        // ...

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

initilizer는 멋진 작업을 수행하지 않았지만 사용자 정의보기 (MUIComponent) 또는 기타 비 사용자 정의 UI 요소 에 대해 시도한 변경 사항 은 단순히 응용 프로그램에 나타나지 않았습니다.

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

}

"badInst"와 "goodInst"의 차이점은 다음과 같습니다.

  • badInst는 활동의 findViewByID를 사용합니다.
  • goodInst는 레이아웃을 확장하고 확장 된 레이아웃을 사용하여 조회를 수행합니다.

발견 빈센트는 동일한 솔루션을 가지고 ... 그리고 그의 대답의 짧은 ... +1 그의 대신 :)
— DevByStarlight

1

이것은 Wear 용 맞춤 구성 요소로 나에게 발생했지만 일반적인 조언입니다. Stub (예 : I was using WatchViewStub) 을 사용 하는 경우 findViewById()아무 곳에 나 전화를 걸 수 없습니다 . 스텁 내부의 모든 것이 먼저 팽창되어야합니다 setContentView(). 따라서 이런 일이 일어나기를 기다리려면 다음과 같이 작성해야합니다.

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

0

내 문제는 오타였습니다. android.id대신 (점)을 썼습니다 android:id. :피

분명히 내 사용자 정의 구성 요소 xml에는 구문 검사가 없습니다. :(


0

같은 문제가있었습니다.

아이들이 거의없는 레이아웃이있었습니다. 하나의 생성자에서 다른 자식에 대한 참조 (context.findViewById 사용)를 얻으려고했습니다. 두 번째 자식이 레이아웃에서 더 정의 되었기 때문에 작동하지 않았습니다.

다음과 같이 해결했습니다.

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

아이들의 순서가 반대라면 잘 되겠지만, 일반적으로 위와 같이해야한다고 생각합니다.


1
일반적으로 findViewById의 생성자에서 사용해서는 안되며 View, 대신 초기화 코드를 OnFinishInflate?
— Sanjay Manohar 2012

0

findViewById()방법은 때때로 반환 null레이아웃의 루트가 전혀없는 경우 android:id속성을. 레이아웃 xml 파일 생성을위한 Eclipse 마법사 android:id는 루트 요소에 대한 속성을 자동으로 생성하지 않습니다 .


0

제 경우에는 뷰가 뷰가 아닌 부모에있었습니다. 제가 호출하려고했습니다. 그래서 자식 뷰에서 다음을 호출해야했습니다.

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

0

'깨끗한'옵션이 저에게 효과적이었습니다.

제 경우 근본 원인은 소스 코드가 네트워크 공유에 있고 워크 스테이션과 파일 서버가 올바르게 동기화되지 않았고 5 초 차이가 났기 때문입니다. Eclipse에서 생성 된 파일의 타임 스탬프는 워크 스테이션의 시계에 따라 과거 (파일 서버에서 할당되기 때문)이므로 Eclipse가 생성 된 파일과 소스 파일 간의 종속성을 잘못 해석합니다. 이 경우 잘못된 타임 스탬프에 의존하는 증분 빌드 대신 완전한 재 빌드를 강제하기 때문에 '정리'가 작동하는 것처럼 보입니다.

워크 스테이션에서 NTP 설정을 수정 한 후에는 문제가 다시 발생하지 않았습니다. 적절한 NTP 설정이 없으면 시계가 빠르게 표류하므로 몇 시간마다 발생합니다.


의 의견이를 추가해야 대답 위
— 쭝 응웬

0

찾아 볼 답변에 또 다른 사소한 실수를 추가하려면 :

실제로 올바른 레이아웃 XML 파일을 편집하고 있는지 확인하십시오.


0

모든 레이아웃 폴더에서보기 ID를 업데이트하는 것을 잊었 기 때문에 동일한 문제가 발생했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.