onCreate()でビューにアクセスするNullPointerException


114

これは、StackOverflowに頻繁に投稿される問題に対する標準的な質問です。

チュートリアルに従っています。ウィザードを使用して新しいアクティビティを作成しました。私が手NullPointerExceptionにメソッドを呼び出すしようとしたときViewに得られたS findViewById()私の活動ではonCreate()

活動onCreate()

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    View something = findViewById(R.id.something);
    something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}

レイアウトXML(fragment_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="packagename.MainActivity$PlaceholderFragment" >

    <View
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/something" />

</RelativeLayout>

回答:


70

チュートリアルはおそらく時代遅れであり、ウィザードで生成されたコードが好むフラグメントベースのUIではなく、アクティビティベースのUIを作成しようとしています。

ビューはフラグメントレイアウト(fragment_main.xml)にあり、アクティビティレイアウト(activity_main.xml)にはありません。onCreate()ライフサイクルの早い段階でアクティビティビューの階層でそれを見つけるには早すぎるため、a nullが返されます。メソッドを呼び出すnullと、NPE が発生します。

推奨される解決策は、コードをフラグメントに移動し、拡張されたフラグメントレイアウトをonCreateView()呼び出すことfindViewById()ですrootView

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
  View rootView = inflater.inflate(R.layout.fragment_main, container,
      false);

  View something = rootView.findViewById(R.id.something); // not activity findViewById()
  something.setOnClickListener(new View.OnClickListener() { ... });

  return rootView;
}

補足として、フラグメントレイアウトは最終的にアクティビティビュー階層の一部になりfindViewById()、フラグメントトランザクションが実行された後にのみアクティビティで検出可能になります。保留中のフラグメントトランザクションは、super.onStart()後で実行されonCreate()ます。


findViewByIdパーツはonActivityCreatedにある必要があります。
Zar E Ahmer

@ネプスターそれはすることができますが、する必要はありません。
laalto

アクティビティがフラグメントにまだアタッチされていない場合があります。
Zar E Ahmer

1
@Nepsterそして、それを呼び出す理由だfindViewById()rootViewとないの活動に。
laalto

10

OnStart()メソッドを試してみてください

View view = getView().findViewById(R.id.something);

またはのgetView().findViewByIdメソッドを使用してビューを宣言しますonStart()

ビューのクリックリスナーを宣言 anyView.setOnClickListener(this);


私にとっては、フラグメントがxmlで宣言されているフラグメントのonCreateView内の兄弟ビューにアクセスしようとしたため、これは役に立ちました。親がインフレートを完了していないため、兄弟ビューはonCreateViewでは依然としてnullでしたが、onStartでは次のようになりました:
Daniel Wilson

3

アクセスするビューをフラグメントのonViewCreatedメソッドにシフトしてみてください。onCreateメソッドでビューにアクセスしようとすると、ビューがそのときにレンダリングされず、結果としてnullポインター例外が発生することがあります。

 @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
     View something = findViewById(R.id.something);
     something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

     if (savedInstanceState == null) {
           getSupportFragmentManager().beginTransaction()
            .add(R.id.container, new PlaceholderFragment()).commit();
    }
 }

2

同意します。これは、Android開発に取り掛かったとき、フラグメントがどのように機能するかをよく理解していないため、これは典型的なエラーです。混乱を軽減するために、私が最初にアプリケーションに投稿した簡単なサンプルコードを作成し、Androidエミュレーターで停止しましたでが、ここにも投稿しました。

次に例を示します。

public class ContainerActivity extends FragmentActivity implements ExampleFragment.Callback
{
    @Override
    public void onCreate(Bundle saveInstanceState)
    {
        super.onCreate(saveInstanceState);
        this.setContentView(R.layout.activity_container);
        if (saveInstanceState == null)
        {               
             getSupportFragmentManager().beginTransaction()
                .add(R.id.activity_container_container, new ExampleFragment())
                .addToBackStack(null)
             .commit();
        }
        getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
        {
            public void onBackStackChanged()
            {
                int backCount = getSupportFragmentManager().getBackStackEntryCount();
                if (backCount == 0)
                {
                    finish();
                }
            }
        });
    }

    @Override
    public void exampleFragmentCallback()
    {
        Toast.makeText(this, "Hello!", Toast.LENGTH_LONG).show();
    }
}

activity_container.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/activity_container_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

ExampleFragment:

public class ExampleFragment extends Fragment implements View.OnClickListener
{
    public static interface Callback
    {
        void exampleFragmentCallback();
    }

    private Button btnOne;
    private Button btnTwo;
    private Button btnThree;

    private Callback callback;

    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);
        try
        {
            this.callback = (Callback) activity;
        }
        catch (ClassCastException e)
        {
            Log.e(this.getClass().getSimpleName(), "Activity must implement Callback interface.", e);
            throw e;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_example, container, false);

        btnOne = (Button) rootView.findViewById(R.id.example_button_one);
        btnTwo = (Button) rootView.findViewById(R.id.example_button_two);
        btnThree = (Button) rootView.findViewById(R.id.example_button_three);

        btnOne.setOnClickListener(this);
        btnTwo.setOnClickListener(this);
        btnThree.setOnClickListener(this);
        return rootView;
    }

    @Override
    public void onClick(View v)
    {
        if (btnOne == v)
        {
            Toast.makeText(getActivity(), "One.", Toast.LENGTH_LONG).show();
        }
        else if (btnTwo == v)
        {
            Toast.makeText(getActivity(), "Two.", Toast.LENGTH_LONG).show();
        }
        else if (btnThree == v)
        {
            callback.exampleFragmentCallback();
        }
    }
}

fragment_example.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <Button
            android:id="@+id/example_button_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="30dp"
            android:text="@string/hello" 
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"/>

        <Button
            android:id="@+id/example_button_two"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/example_button_one"
            android:layout_alignRight="@+id/example_button_one"
            android:layout_below="@+id/example_button_one"
            android:layout_marginTop="30dp"
            android:text="@string/hello" />

        <Button
            android:id="@+id/example_button_three"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/example_button_two"
            android:layout_alignRight="@+id/example_button_two"
            android:layout_below="@+id/example_button_two"
            android:layout_marginTop="30dp"
            android:text="@string/hello" />

</RelativeLayout>

これは有効な例です。アクティビティを使用してフラグメントを表示し、そのフラグメント内のイベントを処理する方法を示しています。また、含まれているアクティビティと通信する方法も説明します。


1
この例では、FragmentActivityにandroid-support-v4ライブラリとサポートフラグメントマネージャーを使用しています。
EpicPandaForce 2014

1
さらに完全な例は、stackoverflow.com
questions / 24840509 /…で

1
ただしOtto、コールバックの代わりに通信に使用Butterknifeし、ビューを挿入するために使用する必要があります。
EpicPandaForce

2

ビュー「何か」は、アクティビティではなくフラグメントにあるため、アクティビティでアクセスする代わりに、フラグメントクラスでアクセスする必要があります。

PlaceholderFragment.class

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container,
  false);

View something = root .findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... });

return root;
}

2

でUI要素にアクセスしようとしていますonCreate()が、onCreateView()メソッドでフラグメントビューを作成できるため、それらにアクセスするには早すぎます。そしてonActivityCreated()、この状態ではアクティビティが完全にロードされているため、メソッドはそれらのアクションを処理するのに信頼できます。


1

以下をactivity_main.xmlに追加します

<fragment
    android:id="@+id/myFragment"
    android:name="packagename.MainActivity$PlaceholderFragment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
</fragment>

0

でビューを宣言したので、フラグメントのメソッドでfragment_main.xmlNPEを取得するコード部分を移動しますonCreateView()。これで問題が解決するはずです。


0

上記の投稿されたコードで質問に問題があります:oncreateメソッドでR.layout.activity_mainを使用していますが、xmlファイル名は "fragment_main.xml"です。これは、fragment_main.xmlファイルのビューを取得しようとしていることを意味しますこれは表示されていないため、nullポインタ例外が発生します。次のようにコードを変更します。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_main);// your xml layout ,where the views are

    View something = findViewById(R.id.something);
    something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}

0

重要なことを覚えておく必要があります。NullPointerExceptionは、変数を宣言し、値を割り当てる前にその値を取得しようとすると発生します。


0

使用onViewCreated()メソッドの使用またはフラグメントからの眺めを呼び出すたび。

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
      View v = view.findViewById(R.id.whatever)
}

0

とメソッドをNullPointerException呼び出した後も同じようにリスナーを初期化しています。findViewById() onCreate()onCreateView()

しかし、私が使用したonActivityCreated(Bundle savedInstanceState) {...}場合、それは機能します。それで、にアクセスしGroupViewてリスナーを設定できました。

お役に立てれば幸いです。


0

ほとんどすべての開発者によって使用されるビューを見つけるための最も人気のあるライブラリ。

バターナイフ

私ができる限り、彼らは適切な方法論で見解を見つけることを説明する十分な答えです。しかし、Android開発者であり、日常的にコードを頻繁に使用している場合は、バターナイフを使用できます。これにより、ビューを見つける時間を大幅に節約でき、そのためのコードを書く必要がありません。2〜3ステップで、ミリ秒単位でビューを見つけることができます。 。

アプリレベルのGradleに依存関係を追加します。

implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

バターナイフのプラグインを追加します。

File -> Settings -> plugins-> 

次に、Android ButterKnife Zeleznyを検索してプラグインをインストールし、スタジオを再起動すれば完了です。

次に、アクティビティのOncreateメソッドに移動して、layout_nameを右クリックし、生成ボタンをタップしてバターナイフ注入オプションを選択すると、以下のようにビュー参照が自動的に作成されます。

    @BindView(R.id.rv_featured_artist)
    ViewPager rvFeaturedArtist;
    @BindView(R.id.indicator)
    PageIndicator indicator;
    @BindView(R.id.rv_artist)
    RecyclerView rvArtist;
    @BindView(R.id.nsv)
    NestedScrollingView nsv;
    @BindView(R.id.btn_filter)
    Button btnFilter;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.