Dans les rapports d'erreur de la console développeur, je vois parfois des rapports avec un problème NPE. Je ne comprends pas ce qui ne va pas avec mon code. Sur l'émulateur et mon application de périphérique fonctionne bien sans forcecloses, cependant certains utilisateurs obtiennent NullPointerException dans la classe de fragments lorsque la méthode getActivity () est appelée.
Activité
pulic class MyActivity extends FragmentActivity{
private ViewPager pager;
private TitlePageIndicator indicator;
private TabsAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
pager = (ViewPager) findViewById(R.id.pager);
indicator = (TitlePageIndicator) findViewById(R.id.indicator);
adapter = new TabsAdapter(getSupportFragmentManager(), false);
adapter.addFragment(new FirstFragment());
adapter.addFragment(new SecondFragment());
indicator.notifyDataSetChanged();
adapter.notifyDataSetChanged();
// push first task
FirstTask firstTask = new FirstTask(MyActivity.this);
// set first fragment as listener
firstTask.setTaskListener((TaskListener) adapter.getItem(0));
firstTask.execute();
}
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment currentFragment = adapter.getItem(position);
((Taskable) currentFragment).executeTask();
}
@Override
public void onPageScrolled(int i, float v, int i1) {}
@Override
public void onPageScrollStateChanged(int i) {}
});
}
Classe AsyncTask
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
Classe de fragment
public class FirstFragment extends Fragment immplements Taskable, TaskListener{
public FirstFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_view, container, false);
}
@Override
public void executeTask() {
FirstTask firstTask = new FirstTask(MyActivity.this);
firstTask.setTaskListener(this);
firstTask.execute();
}
@Override
public void onTaskComplete(T result) {
// NPE is here
Resources res = getActivity().getResources();
...
}
}
Peut-être que cette erreur se produit lorsque les applications reprennent en arrière-plan. Dans ce cas, comment dois-je gérer cette situation correctement?
android
android-fragments
android-activity
android-asynctask
nullpointerexception
Georgy Gobozov
la source
la source
Réponses:
Il semble que j'ai trouvé une solution à mon problème. De très bonnes explications sont données ici et ici . Voici mon exemple:
L'idée principale de ce code est que, tout en exécutant votre application normalement, vous créez de nouveaux fragments et les passez à l'adaptateur. Lorsque vous reprenez votre gestionnaire de fragments d'application possède déjà l'instance de ce fragment et vous devez l'obtenir du gestionnaire de fragments et le transmettre à l'adaptateur.
METTRE À JOUR
En outre, c'est une bonne pratique lorsque vous utilisez des fragments pour vérifier isAdded avant d'appeler getActivity (). Cela permet d'éviter une exception de pointeur nul lorsque le fragment est détaché de l'activité. Par exemple, une activité peut contenir un fragment qui envoie une tâche asynchrone. Une fois la tâche terminée, l'écouteur onTaskComplete est appelé.
Si nous ouvrons le fragment, poussons une tâche, puis appuyons rapidement pour revenir à une activité précédente, lorsque la tâche est terminée, il tentera d'accéder à l'activité dans onPostExecute () en appelant la méthode getActivity (). Si l'activité est déjà détachée et que cette vérification n'est pas là:
puis l'application se bloque.
la source
isAdded()
avant chaque accès ... rend le code laid.if(isAdded())
ouif(getActivity() != null)
Ok, je sais que cette question est en fait résolue mais j'ai décidé de partager ma solution pour cela. J'ai créé une classe parent abstraite pour mon
Fragment
:Comme vous pouvez le voir, j'ai ajouté un écouteur donc, chaque fois que je devrai obtenir
Fragments
Activity
au lieu de standardgetActivity()
, je devrai appelerla source
Le meilleur moyen de s'en débarrasser est de conserver la référence d'activité lorsqu'elle
onAttach
est appelée et d'utiliser la référence d'activité partout où cela est nécessaire, par exempleModifié, car
onAttach(Activity)
est amorti etonAttach(Context)
est maintenant utiliséla source
getActivity()
renvoie null, c'est parce que vous n'êtes plus dans une activité. Il s'agit d'une solution de contournement sale.N'appelez pas de méthodes dans le fragment qui nécessitent getActivity () jusqu'à onStart dans l'activité parent.
la source
J'ai été lutte contre ce type de problème depuis un certain temps et je pense avoir trouvé une solution fiable.
Il est assez difficile de savoir avec certitude que cela
this.getActivity()
ne reviendra pasnull
pour unFragment
, surtout si vous faites face à tout type de comportement réseau qui donne à votre code suffisamment de temps pour se retirerActivity
références.Dans la solution ci-dessous, je déclare une petite classe de gestion appelée
ActivityBuffer
. Essentiellement, celaclass
concerne le maintien d'une référence fiable à un propriétaireActivity
et la promesse d'exécuter desRunnable
s dans unActivity
contexte valide chaque fois qu'une référence valide est disponible. LesRunnable
s sont planifiés pour être exécutés sur le thread d'interface utilisateur immédiatement s'ilsContext
sont disponibles, sinon l'exécution est différée jusqu'à ce que celaContext
soit prêt.Au niveau de sa mise en œuvre, il faut veiller à appliquer les méthodes du cycle de vie pour coïncider avec le comportement décrit ci-dessus par Pawan M :
Enfin, dans tous les domaines au sein de votre
Fragment
qui s'étendBaseFragment
que vous n'êtes pas digne de confiance sur un appel àgetActivity()
, il suffit d'appelerthis.getActivityBuffer().safely(...)
et de déclarer unActivityBuffer.IRunnable
pour la tâche!Le contenu de votre
void run(final Activity pActivity)
est alors garanti de s'exécuter le long du fil d'interface utilisateur.Le
ActivityBuffer
peut alors être utilisé comme suit:la source
la source
Je sais que c'est une vieille question mais je pense que je dois y répondre parce que mon problème n'a pas été résolu par d'autres.
tout d'abord: j'ajoutais dynamiquement des fragments en utilisant fragmentTransactions. Deuxièmement: mes fragments ont été modifiés à l'aide d'AsyncTasks (requêtes DB sur un serveur). Troisièmement: mon fragment n'a pas été instancié au début de l'activité Quatrièmement: j'ai utilisé une instanciation de fragment personnalisée "créer ou charger" afin d'obtenir la variable de fragment. Quatrièmement: l'activité a été recréée en raison d'un changement d'orientation
Le problème était que je voulais "supprimer" le fragment à cause de la réponse à la requête, mais le fragment a été créé incorrectement juste avant. Je ne sais pas pourquoi, probablement à cause du "commit" qui sera fait plus tard, le fragment n'a pas encore été ajouté au moment de le supprimer. Par conséquent, getActivity () renvoyait null.
Solution: 1) J'ai dû vérifier que j'essayais correctement de trouver la première instance du fragment avant d'en créer un nouveau 2) J'ai dû mettre serRetainInstance (true) sur ce fragment afin de le conserver par le changement d'orientation (pas de backstack nécessaire donc pas de problème) 3) Au lieu de "recréer ou obtenir un vieux fragment" juste avant de "le retirer", je mets directement le fragment au début de l'activité. L'instanciation au démarrage de l'activité au lieu de «charger» (ou instancier) la variable de fragment avant de la supprimer a empêché les problèmes de getActivity.
la source
Dans Kotlin, vous pouvez essayer de cette façon de gérer la condition null getActivity ().
Il vérifiera que l'activité est nulle ou non et s'il n'est pas nul, exécutera le code interne.
la source