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(...)そのコンストラクターの末尾に「epic fail」の直前にlogcatで正常に表示されます。

なぜfoonullなのですか?

回答:


182

コンストラクタで、のsuper(context)代わりに持っていたからsuper(context, attrs)です。

IDなどの属性を渡さない場合、ビューにはIDがないため、そのIDを使用して検索することはできません。:-)


1
あなた自身の質問に答えることができるのはいつもうれしいです:)あなたもあなたの受け入れられた答えとしてマークしてください。
MattC、2009年

確かに。SOが私に許可したときにそれを行います(「2日で自分の回答を受け入れることができます。」)
Chris Boyle

4
また、(MyCustomView) foo = findViewById(R.id.foo);beのような行はありませんMyCustomView foo = (MyCustomView) findViewById(R.id.foo);か?
ジェレミーローガン

3
同じ問題を抱えていた、私の場合、私はsetContentView().. XD忘れていた
トム・ブリト

vogella.comでそのようなことを行うための良い例があります:vogella.com/articles/AndroidCustomViews/article.html
Wolkenjaeger

27

カスタムビューでコンストラクターをオーバーライドしましたが、attrs parameteを使用せずにスーパーコンストラクターを呼び出したため、同じ問題が発生しました。それはコピーペーストです)

私の以前のコンストラクタバージョン:

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

今私が持っています:

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

そしてそれはうまくいきます!


ここで同じ問題。ちなみに私もコピーペーストエラーでした。
KurtCobain 14

同じことが私にも起こりました。Stackoverflowの最も正しい答え。AttributeSet attrsを再度追加すると、すべてが正常です。
2015

私たちは皆、カスタムビューで同じチュートリアルを調べたと思います;)このエラーにより、無意味なデバッグに0.5時間かかりました...
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に間違った文字列が表示されるなど、他の場合にもこれに気づきました。なぜこれが発生するのか本当にわかりません。
クラゲ

これは私にあまりにも長い間悲しみを与えていました-クリーンは本当に私のためにそれを修正しました。
ニコラスMTエリオット、

1
確かにクリーンアップ。うわー、それは最低だ!
TimBüthe、2011年

11

同じ問題ですが、解決策が異なります。電話しませんでした

setContentView(R.layout.main)

ここで述べたようにビューを見つけようとする前に


現在の関連ビューではなく他のビューの要素を取得している場合、これが解決策だと思います。
StarCub

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)ステートメントがステートメントの前に呼び出されることを確認して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);
    }       
}

初期化プログラムは特別なことをしていませんでしたが、カスタムビュー(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のカスタムコンポーネントで発生しましたが、一般的なアドバイスです。スタブを使用している場合(たとえば、を使用していた場合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。:P

どうやら、私のカスタムコンポーネントxml内には構文チェックがありません。:(


0

同じ問題がありました。

子供が少ないレイアウトでした。1つのコンストラクターから、(context.findViewByIdを使用して)他の子への参照を取得しようとしました。2番目の子がレイアウトでさらに定義されているため、機能していませんでした。

私はこのようにそれを解決しました:

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設定がないと、クロックが速くドリフトするため、数時間ごとに発生します。


上記の回答のコメントにこれを追加する必要があります
Trung Nguyen

0

ささいな間違いを別の答えに追加して、以下の点を確認します。

実際に正しいレイアウトXMLファイルを編集していることを確認してください...


0

すべてのレイアウトフォルダーのビューIDを更新するのを忘れたため、同じ問題が発生しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.