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.