OnCreate () 'deki görünümlere erişen NullPointerException


114

Bu, StackOverflow'da sıklıkla yayınlanan bir soruna yönelik kanonik bir sorudur.

Bir öğreticiyi takip ediyorum. Bir sihirbaz kullanarak yeni bir aktivite oluşturdum. Ben olsun NullPointerExceptionbir yöntemi çağırmak çalışırken Viewelde s findViewById()benim aktivitesinde onCreate().

Aktivite 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();
    }
}

Düzen 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>

Yanıtlar:


70

Öğretici büyük olasılıkla güncelliğini yitirmiş, sihirbaz tarafından üretilen kod tarafından tercih edilen parça tabanlı kullanıcı arabirimi yerine etkinlik tabanlı bir kullanıcı arabirimi oluşturmaya çalışıyor.

Görünüm, parça düzeninde ( fragment_main.xml), etkinlik düzeninde ( activity_main.xml) değil. onCreate()yaşam döngüsünün etkinlik görünümü hiyerarşisinde bulmak için çok erken ve a nulldöndürülür. Bir yöntemi çağırmak NPE'ye nullneden olur.

Tercih edilen çözüm, şişirilmiş parça düzenini onCreateView()çağırarak kodu parçaya taşımaktır :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;
}

Bir yan not olarak, parça düzeni en sonunda etkinlik görünümü hiyerarşisinin bir parçası olacak ve etkinlikle keşfedilebilir, findViewById()ancak yalnızca parça işlemi çalıştırıldıktan sonra olacaktır. Bekleyen parça işlemleri daha super.onStart()sonra yürütülür onCreate().


findViewById bölümü onActivityCreated içinde olmalıdır.
Zar E Ahmer

@Nepster Olabilir, ancak zorunlu değildir.
laalto

Bazen etkinlik henüz parçaya bağlanmaz.
Zar E Ahmer

1
@Nepster Ve çağıran yüzden en findViewById()üstünde rootViewdeğil aktivitesi üzerine.
laalto

10

OnStart()Yöntemi dene ve sadece kullan

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

veya getView().findViewByIdyöntemini kullanarak herhangi bir Görünüm BildirinonStart()

Tıklama işleyicisinin görünümde olduğunu bildirmek için anyView.setOnClickListener(this);


Benim için bu yararlı oldu çünkü bir parçanın xml'de bildirildiği onCreateView içindeki kardeş görünümüne erişmeye çalışıyordum. Kardeş görünümleri onCreateView'de hala boştu çünkü ebeveyn şişirmeyi bitirmemişti, ancak onStart'ta vardı :)
Daniel Wilson

3

Erişim görünümlerinizi onViewCreated parça yöntemine kaydırmaya çalışın, çünkü bazen onCreate yöntemindeki görünümlere erişmeye çalıştığınızda, bunlar boş işaretçi istisnasıyla sonuçlanan zamanda işlenmezler.

 @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

Kabul edildi, bu tipik bir hata çünkü insanlar Android geliştirme üzerinde çalışmaya başladıklarında Fragments'ın nasıl çalıştığını gerçekten anlamıyorlar. Karışıklığı hafifletmek için, Uygulama'da ilk olarak yayınladığım basit bir örnek kod oluşturdum android emülatörde durduruldu , ancak burada da gönderdim.

Bir örnek şudur:

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>

Ve bu geçerli bir örnek olmalı, bir Parçayı görüntülemek için bir Etkinliği nasıl kullanabileceğinizi ve bu Parçadaki olayları nasıl işleyebileceğinizi gösterir. Ve ayrıca içeren Aktivite ile nasıl iletişim kurulacağını.


1
Bu örnek, FragmentActivity için android-support-v4 kitaplığını ve destek parçası yöneticisini kullanır.
EpicPandaForce


1
Kullanmak gerekmesine rağmen Ottoiletişimin yerine geri aramaları ve kullanıma Butterknifeenjekte görünümlerine.
EpicPandaForce

2

Görünüm "bir şey" parçalıdır ve etkinlik içinde değildir, bu nedenle ona etkinlik içinde erişmek yerine, aşağıdaki gibi parça sınıfından ona erişmelisiniz.

PlaceholderFragment.class içinde

@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 öğelerine onCreate()ancak içinde erişmeye çalışıyorsunuz , onCreateView()yöntemde parça görünümlerinde oluşturulabileceğinden, bunlara erişmek için henüz çok erken . Ve onActivityCreated()yöntem, bunlar üzerindeki herhangi bir eylemi ele almak için güvenilirdir, çünkü etkinlik bu durumda tamamen yüklenir.


1

Aşağıdakileri activity_main.xml dosyanıza ekleyin

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

0

Görünümünüzü içinde bildirdiğiniz için fragment_main.xml, bu kod parçasını, parça onCreateView()yönteminde NPE'yi aldığınız yere taşıyın . Bu sorunu çözmelidir.


0

soruda yukarıdaki kodda bir sorun var: oncreate yönteminde R.layout.activity_main kullanıyorsunuz, ancak xml dosyalarının adı "fragment_main.xml", fragment_main.xml dosyasının görünümünü almaya çalıştığınız anlamına geliyor gösterilmediği için boş gösterici istisnası verir. kodu şu şekilde değiştirin:

@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

Önemli olan şeyi hatırlamanız gerekir: NullPointerException, değişkeninizi bildirdiğinizde ve ona değer atamadan önce değerini geri almaya çalıştığınızda oluşur.


0

Parçalardan görünümleri kullanırken veya çağırırken onViewCreated () Yöntemini kullanın .

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

0

NullPointerExceptionÇağrı findViewById() onCreate()ve onCreateView()yöntemlerden sonra bir dinleyiciyi başlatırken aynı şey var .

Ama kullandığımda onActivityCreated(Bundle savedInstanceState) {...}işe yarıyor. Böylece GroupViewdinleyicime erişebilir ve ayarlayabilirim.

Umarım yardımcı olur.


0

Hemen hemen her geliştirici tarafından kullanılan görünümleri bulmak için en popüler kitaplık.

Tereyağı bıçağı

Elimden geldiğince, uygun metodoloji ile görüş bulmayı açıklayan yeterli cevaplar. Ancak, android geliştiriciyseniz ve günlük olarak sık sık kod yazıyorsanız, o zaman görünüm bulmada çok zaman kazandıran ve bunun için kod yazmadığınız tereyağı bıçağını kullanabilirsiniz, 2-3 adımda milisaniye cinsinden görünümleri bulabilirsiniz. .

Uygulama düzeyinde kademede bağımlılık ekleyin:

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

Tereyağı bıçağı için eklenti ekleyin:

File -> Settings -> plugins-> 

Ardından Android ButterKnife Zelezny'yi arayın ve eklentiyi kurun ve stüdyonuzu yeniden başlatın ve işiniz bitti.

Şimdi etkinliğinizin Oncreate yöntemine gidin ve layout_name üzerine sağ tıklayın ve oluştur düğmesine dokunun ve butterknife enjeksiyon seçeneğini seçin ve görünüm referanslarınız aşağıda belirtildiği gibi otomatik olarak oluşturulacaktır:

    @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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.