web-dev-qa-db-fra.com

NullPointerException accédant aux vues dans onCreate ()

Ceci est une question canonique pour un problème fréquemment posté sur StackOverflow.

Je suis un tutoriel. J'ai créé une nouvelle activité à l'aide d'un assistant. Je reçois NullPointerException lorsque j'essaie d'appeler une méthode sur Views obtenue 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();
    }
}

Layout 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>
112
laalto

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

La vue se trouve dans la présentation du fragment (fragment_main.xml) Et non dans la présentation de l'activité (activity_main.xml). onCreate() est trop tôt dans le cycle de vie pour le trouver dans la hiérarchie de la vue d'activité et un null est renvoyé. L'appel d'une méthode sur null provoque le NPE.

La solution recommandée consiste à déplacer le code vers le fragment onCreateView(), en appelant findViewById() sur la présentation 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 guise de remarque, la disposition des fragments fera finalement partie de la hiérarchie de la vue d’activité et sera découvrable avec l’activité findViewById(), mais seulement après que la transaction de fragment aura été exécutée. Les transactions de fragments en attente sont exécutées dans super.onStart() après onCreate().

69
laalto

Essayez la méthode OnStart() et utilisez simplement

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

ou Déclarez n'importe quelle vue en utilisant la méthode getView().findViewById dans onStart()

Déclarez l'auditeur de clic visionné par anyView.setOnClickListener(this);

10
Tarun Sharma

Essayez de déplacer vos vues d'accès vers la méthode de fragment onViewCreated, car parfois, lorsque vous essayez d'accéder aux vues dans la méthode onCreate, celles-ci ne sont pas restituées au moment de la création de l'exception de pointeur 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();
    }
 }
3
Sarthak Sharma

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

2
Krishna

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

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>

Exemple de fragment:

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 de ce fragment. Et aussi comment communiquer avec l'activité contenante.

2
EpicPandaForce

La vue "quelque chose" est en fragment et non en activité. Au lieu d'y accéder en activité, vous devez y accéder dans la classe fragment telle que

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

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>
1
Joyce

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

0
Rohit Goyal

La bibliothèque la plus populaire pour trouver des vues, utilisée par presque tous les développeurs.

ButterKnife

Comme je peux, il y a suffisamment de réponses pour expliquer la recherche de points de vue avec une méthodologie appropriée. Mais si vous êtes Android développeur et code fréquemment sur une base quotidienne, vous pouvez utiliser le couteau à beurre qui vous fait gagner beaucoup de temps pour la recherche de vues et pour lequel vous n'avez pas le code d'écriture, With in 2 -3 étapes pour trouver des vues en millisecondes.

Ajouter une dépendance dans le niveau d'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-> 

Recherchez ensuite Android ButterKnife Zelezny , installez le plug-in, redémarrez votre studio et vous avez terminé.

Maintenant, allez simplement à la méthode Oncreate de votre activité et cliquez 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;
0
Rishabh Saxena

Utilisez onViewCreated () Méthode lorsque 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)
}
0
Sandip Savaliya

J'ai le même NullPointerException initialisant un écouteur après avoir appelé les méthodes findViewById()onCreate() et onCreateView().

Mais quand j'ai utilisé le onActivityCreated(Bundle savedInstanceState) {...} cela fonctionne. Je pouvais donc accéder au GroupView et définir mon auditeur.

J'espère que cela vous sera utile.

0
clebertx

Vous devez vous rappeler que l’important est que: 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.

0
Mohan Munisifreddy

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 du fichier xml est "fragment_main.xml", ce qui signifie que vous essayez d'obtenir la vue du fichier fragment_main.xml. qui n'est pas affiché, donc il donne une exception de pointeur nulle. changer 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();
    }
}
0
Akshay Paliwal