onCreate ()에서 뷰에 액세스하는 NullPointerException


114

StackOverflow에 자주 게시되는 문제에 대한 표준 질문입니다.

튜토리얼을 따르고 있습니다. 마법사를 사용하여 새 활동을 만들었습니다. 내가 얻을 NullPointerException에 메서드를 호출 할 때 View얻을의 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가 반환됩니다. 에서 메서드를 호출하면 nullNPE가 발생합니다.

선호되는 해결책은 부풀려진 조각 레이아웃을 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

@Nepster 그럴 수 있지만 꼭 그럴 필요는 없습니다.
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 여전히 널 있었지만, ONSTART에 그들은 :)했다
다니엘 윌슨에게

3

때때로 onCreate 메서드에서 뷰에 액세스하려고 할 때 null 포인터 예외가 발생하는 시점에 렌더링되지 않기 때문에 액세스 뷰를 조각의 onViewCreated 메서드로 전환 해보십시오.

 @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 개발 작업을 시작할 때 프래그먼트가 작동하는 방식을 이해하지 못하는 경우가 많기 때문에 이것은 일반적인 오류입니다. 혼란을 줄이기 위해 원래 Application is stops in android emulator 에 게시 한 간단한 예제 코드를 만들었지 만 여기에도 게시했습니다.

예는 다음과 같습니다.

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>

그리고 그것은 유효한 예제 여야합니다. Activity를 사용하여 Fragment를 표시하고 해당 Fragment에서 이벤트를 처리하는 방법을 보여줍니다. 또한 포함 된 활동과 통신하는 방법도 있습니다.


1
이 예에서는 FragmentActivity 및 지원 프래그먼트 관리자에 android-support-v4 라이브러리를 사용합니다.
EpicPandaForce

1
더욱 완벽한 예에서 볼 수 stackoverflow.com/questions/24840509/...
EpicPandaForce

1
당신은 사용해야하지만 Otto통신 대신 콜백 및 사용을 위해 Butterknife분사 전망이다.
EpicPandaForce 2015 년

2

뷰 "something"은 활동이 아닌 조각에 있으므로 활동에서 액세스하는 대신 다음과 같은 조각 클래스에서 액세스해야합니다.

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

onCreate()but 에서 UI 요소에 액세스하려고하는데 , 프래그먼트 뷰에서 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.xml 했으므로 onCreateView()조각 의 메서드 에서 NPE를 가져 오는 코드 조각을 이동합니다 . 이렇게하면 문제가 해결됩니다.


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

거의 모든 개발자가 사용하는 뷰를 찾는 데 가장 많이 사용되는 라이브러리입니다.

버터 칼

내가 할 수 있듯이 적절한 방법론으로 견해를 찾는 것을 설명하는 충분한 답변입니다. 하지만 안드로이드 개발자이고 매일 코드를 자주 작성한다면 뷰를 찾는 데 많은 시간을 절약하고 코드를 작성하지 않는 버터 나이프를 사용할 수 있습니다. 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.