web-dev-qa-db-ja.com

findViewById()は、他のコンポーネントではなく、レイアウトXMLのカスタムコンポーネントに対してnullを返します

これらの要素などを含む_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"); }
_

他の要素は正常に検出されましたが、fooはnullに戻ります。 MyCustomViewには、コンストラクターMyCustomView(Context c, AttributeSet a)があり、そのコンストラクターの最後にLog.d(...)が「エピック失敗」の直前にlogcatに正常に表示されます。

なぜfoo nullなのですか?

90
Chris Boyle

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

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

174
Chris Boyle

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

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

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

今私が持っている:

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

そしてそれは動作します!

25

同じ問題がありました。私の間違いは:私が書いた

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

誰かが同じ問題を抱えている場合に備えて、解決策を書きました。

18
Vincent

さまざまな理由があるようです。 Eclipseで「Clean ...」を使用して、同様の問題を解決しました。 (FindViewByIDは以前に機能し、何らかの理由でnullを返し始めました。)

18
jellyfish

同じ問題ですが、別の解決策:私は電話しませんでした

setContentView(R.layout.main)

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

11
Daniel

複数のレイアウトバージョンがある場合(画面密度、SDKバージョンによって異なります)、すべてのバージョンに探している要素が含まれていることを確認してください。

4
M.Q.

setContentView(R.layout.main)ステートメントの前にfindViewById(...)ステートメントを呼び出すようにしてください。

2
Mason

私の場合、カスタムビューはメイン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
gerfmarquez

レイアウト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)またはその他のnon-custom 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

これは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);
            ...
1
Stephen Wylie

私の場合、プロジェクト設定のJava Build Pathでソースにresフォルダーを追加すると、問題は解決しました。

1
Jiwon Park

同じ問題がありました。

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

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

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

子供の順序が逆であればうまくいきますが、一般的には上記のようにする必要があります。

0
Kangur

「クリーン」オプションは私のために働いた。

私の場合、根本的な原因は、ソースコードがネットワーク共有上にあり、ワークステーションとファイルサーバーが正しく同期されず、5秒ずれていたことです。 Eclipseによって作成されたファイルのタイムスタンプは過去のものです(ファイルサーバーによって割り当てられるため)。ワークステーションのクロック。これにより、Eclipseは生成ファイルとソースファイル間の依存関係を誤って解決します。この場合、誤ったタイムスタンプに依存するインクリメンタルビルドではなく、完全な再構築を強制するため、「クリーン」が機能しているように見えます。

ワークステーションのNTP設定を修正すると、問題は二度と発生しません。適切なNTP設定がないと、クロックが高速でドリフトするため、数時間ごとに発生します。

0
diter

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

0
Shanij P.S

別の些細な間違いを答えに追加して、次のことに注意してください。

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

0
usagidon

私の場合、ビューは呼び出そうとしていたビューではなく親にありました。したがって、子ビューでは、次のように呼び出す必要がありました。

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

私の問題はタイプミスでした。私はAndroid.id(ドット)の代わりにAndroid:id。 :P

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

0
JOG

レイアウトのルートに_Android:id_属性がない場合、findViewById()メソッドはnullを返すことがあります。レイアウトxmlファイルを生成するEclipseウィザードは、ルート要素の_Android:id_属性を自動的に生成しません。

0
Santosh