NullPointerException accédant aux vues dans onCreate ()

114

Il s'agit d'une question canonique pour un problème fréquemment publié sur StackOverflow.

Je suis un tutoriel. J'ai créé une nouvelle activité à l'aide d'un assistant. J'obtiens NullPointerExceptionen essayant d'appeler une méthode sur les Views obtenus avec findViewById()dans mon activité onCreate().

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

Mise en page 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>
laalto
la source

Réponses:

70

Le didacticiel est probablement obsolète et tente de créer une interface utilisateur basée sur les activités au lieu de l'interface utilisateur basée sur des fragments préférée par le code généré par l'assistant.

La vue est dans la mise en page de fragment ( fragment_main.xml) et non dans la mise en page d'activité ( activity_main.xml). onCreate()est trop tôt dans le cycle de vie pour le trouver dans la hiérarchie des vues d'activité, et un nullest renvoyé. L'appel d'une méthode sur nullprovoque le NPE.

La solution préférée est de déplacer le code vers le fragment onCreateView(), en faisant appel findViewById()à la disposition du fragment gonflé 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;
}

En remarque, la mise en page de fragment fera éventuellement partie de la hiérarchie de la vue d'activité et pourra être découverte avec l'activité, findViewById()mais seulement après l'exécution de la transaction de fragment. Les transactions de fragment en attente sont exécutées super.onStart()après onCreate().

laalto
la source
La partie findViewById doit être dans onActivityCreated.
Zar E Ahmer
@Nepster Cela peut l'être, mais ce n'est pas obligatoire.
laalto
Parfois, l'activité n'est pas encore attachée au fragment.
Zar E Ahmer
1
@Nepster Et voilà pourquoi appelant findViewById()à rootViewet non sur l' activité.
laalto
10

Essayez la OnStart()méthode et utilisez simplement

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

ou Déclarez une vue en utilisant la getView().findViewByIdméthode dansonStart()

Déclarer l'écouteur de clics lors de l'affichage par anyView.setOnClickListener(this);

Tarun Sharma
la source
Pour moi, cela a été utile parce que j'essayais d'accéder à une vue sœur dans onCreateView d'un fragment, où le fragment a été déclaré en xml. Les vues des frères et sœurs étaient toujours nulles dans onCreateView car le parent n'avait pas fini de gonfler, mais dans onStart, elles l'avaient :)
Daniel Wilson
3

Essayez de déplacer vos vues d'accès vers la méthode onViewCreated du fragment car parfois, lorsque vous essayez d'accéder aux vues dans la méthode onCreate, elles ne sont pas rendues au moment de l'exception de pointeur nul.

 @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();
    }
 }
Sarthak Sharma
la source
2

D'accord, il s'agit d'une erreur typique car les gens ne comprennent souvent pas vraiment le fonctionnement des fragments lorsqu'ils commencent à travailler sur le développement Android. Pour éviter toute confusion, j'ai créé un exemple de code simple que j'ai initialement publié sur L' application est arrêtée dans l'émulateur Android , mais je l'ai également posté ici.

Un exemple est le suivant:

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>

ExempleFragment:

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>

Et cela devrait être un exemple valide, il montre comment vous pouvez utiliser une activité pour afficher un fragment et gérer les événements dans ce fragment. Et aussi comment communiquer avec l'activité contenant.

EpicPandaForce
la source
1
Cet exemple utilise la bibliothèque android-support-v4 pour FragmentActivity et le gestionnaire de fragments de support.
EpicPandaForce
1
un exemple encore plus complet est disponible sur stackoverflow.com/questions/24840509/…
EpicPandaForce
1
Bien que vous deviez utiliser Ottopour la communication au lieu des rappels, et utiliser Butterknifepour injecter des vues.
EpicPandaForce
2

La vue "quelque chose" est fragmentée et non en activité, donc au lieu d'y accéder en activité, vous devez y accéder dans la classe fragment comme

Dans 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;
}
Shubham Goel
la source
2

Vous essayez d'accéder aux éléments de l'interface utilisateur dans le onCreate()mais, il est trop tôt pour y accéder, car dans les vues fragmentées peuvent être créées dans onCreateView()method. Et la onActivityCreated()méthode est fiable pour gérer toutes les actions sur eux, car l'activité est entièrement chargée dans cet état.

Krishna
la source
1

Ajoutez ce qui suit dans votre activity_main.xml

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

Puisque vous avez déclaré votre vue dans le fragment_main.xml, déplacez ce morceau de code là où vous obtenez le NPE dans la onCreateView()méthode du fragment. Cela devrait résoudre le problème.

Rohit Goyal
la source
0

dans le code posté ci-dessus dans la question, il y a un problème: vous utilisez R.layout.activity_main dans la méthode oncreate, mais le nom des fichiers xml est "fragment_main.xml", cela signifie que vous essayez d'obtenir la vue du fichier fragment_main.xml qui n'est pas affiché, il donne donc une exception de pointeur nul. changez le code comme:

@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();
    }
}
Akshay Paliwal
la source
0

Vous devez vous rappeler que la chose importante est: NullPointerException se produit lorsque vous avez déclaré votre variable et que vous essayez de récupérer sa valeur avant de lui attribuer une valeur.

Mohan Munisifreddy
la source
0

Utilisez la méthode onViewCreated () chaque fois que vous utilisez ou appelez des vues à partir de fragments.

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

J'ai la même NullPointerExceptioninitialisation d'un auditeur après l'appel findViewById() onCreate()et les onCreateView()méthodes.

Mais quand je l'ai utilisé, onActivityCreated(Bundle savedInstanceState) {...}cela fonctionne. Ainsi, je pourrais accéder au GroupViewet définir mon auditeur.

J'espère que cela vous sera utile.

Clebertx
la source
0

Bibliothèque la plus populaire pour rechercher des vues, utilisée par presque tous les développeurs.

Couteau à beurre

Comme je peux, leurs réponses sont suffisantes pour expliquer la recherche de points de vue avec une méthodologie appropriée. Mais si vous êtes développeur Android et que vous codez fréquemment au quotidien, vous pouvez utiliser un couteau à beurre, ce qui vous fait gagner beaucoup de temps dans la recherche de vues et vous n'avez pas d'écriture de code pour cela, avec en 2-3 étapes, vous pouvez trouver des vues en millisecondes .

Ajouter une dépendance au niveau de l'application:

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

Ajouter un plugin pour couteau à beurre:

File -> Settings -> plugins-> 

Ensuite, recherchez Android ButterKnife Zelezny et installez le plugin et redémarrez votre studio et vous avez terminé.

Maintenant, allez simplement à la méthode Oncreate de votre activité et faites un clic droit sur votre layout_name et appuyez sur le bouton générer et sélectionnez l'option d'injection Butterknife et vos références de vues seront automatiquement créées comme mentionné ci-dessous:

    @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;
Rishabh Saxena
la source