NullPointerException en Fragment Listener

Tengo una actividad con ViewPager, en el adaptador de ViewPager Proporciono el fragmento para cada posición.

Un fragmento de ejemplo es DebugFragment. He escrito el código fuente a continuación.

public class DebugFragment extends android.support.v4.app.Fragment { private OnFragmentInteractionListener mListener; public interface OnFragmentInteractionListener { void onFragmentInteraction(int someValue); } public static DebugFragment newInstance() { DebugFragment fragment = new DebugFragment(); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mListener.onFragmentInteraction(0); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LocalBroadcastManager.getInstance(getContext()).registerReceiver(mMessageReceiver, new IntentFilter("com.android.example.INITIAL_REQUEST")); } @Override public void onDestroy() { LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mMessageReceiver); super.onDestroy(); } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } @Override public void onResume() { super.onResume(); getUserData(); } public void getUserData() { // Inside Background Thread if (getActivity() == null) { return; } getActivity().runOnUiThread(new Runnable() { @Override public void run() { mListener.onFragmentInteraction(0); // This line throws NPE } }); } 

Mi implementación de la actividad a continuación.

 public class DebugActivity extends AppCompatActivity implements DebugFragment.OnFragmentInteractionListener { // Other Activity Callback @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { DebugFragment debugFragment = ((DebugFragment) mViewPagerAdapter.getRegisteredFragment(2)); if (debugFragment != null) { debugFragment.getUserData(); } } } } } 

Llamo getUserData de mi DebugFragment de onResume de Fragment, BroadcastReceiver, OnActivityResult of Activity.

En algún momento obtengo NullPointerException en getUserData mientras intento acceder a FragmentListener ie mListener. ¿Quiero saber por qué?

Como ya estoy comprobando Actividad nula. ¿No es esto suficiente. ¿Tengo que comprobar si hay nulo de mListener también? Sería genial si alguien me explicara el caso en el que la actividad no será nula, pero mi mListener será nulo. Sólo he mantenido mi actividad en el modo Retrato.

Editar

Mi código de adaptador

 public abstract class TabPagerAdapter extends FragmentPagerAdapter { public TabPagerAdapter(FragmentManager fm) { super(fm); } public abstract View getTabView(int position); } public class SecondaryPagerAdapter extends TabPagerAdapter { private static final int NUM_PAGES = 5; private String tabTitles[] = new String[] { "Today", "New", "Calendar", "In-progress", "Invoices" }; private int[] imageResId = { R.drawable.ic_tab_hired_pro, R.drawable.ic_tab_history, R.drawable.ic_tab_today, R.drawable.ic_tab_inprogress, R.drawable.ic_tab_invoices }; SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>(); public SecondaryPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { switch (position) { case 0: case 1: case 3: return ServiceRequestFragment.newInstance(tabTitles[position]); case 2: return DebugFragment.newInstance(); case 4: return InvoicesFragment.newInstance(); default: throw new RuntimeException("No fragment for this position"); } } @Override public int getCount() { return NUM_PAGES; } @Override public View getTabView(int position) { CustomTab customTab = new CustomTab(DashBoardActivity.this); customTab.bindWith(imageResId[position], tabTitles[position]); return customTab; } @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment) super.instantiateItem(container, position); registeredFragments.put(position, fragment); return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { registeredFragments.remove(position); super.destroyItem(container, position, object); } public Fragment getRegisteredFragment(int position) { return registeredFragments.get(position); } } 

De mi actividad lo llamo como

 mSecondaryPagerAdapter = new SecondaryPagerAdapter(getSupportFragmentManager()); mSecondaryPager = (ViewPager) findViewById(R.id.dashboard_pager); mSecondaryPager.setOffscreenPageLimit(4); mSecondaryPager.setAdapter(mSecondaryPagerAdapter); 

Cuando llama a getActivity().runOnUiThread(new Runnable() {}) , esto enqueues que Runnable para ejecutar en el subproceso de interfaz de usuario después de todo lo demás que ya está en cola en el subproceso de interfaz de usuario, que puede incluir llamadas a onDestroy() mListener a null. Esto significa que es posible que su aplicación esté cerrándose mientras se emite una emisión. Aunque esto no debería ser un problema en el caso normal, porque mListener registro de su receptor antes de limpiar el mListener , es posible que el Runnable haya sido en colado después de esto, Por lo que el oyente es nulo cuando se ejecuta.

Para evitar el NPE, debe comprobar mListener == null en el Runnable. Sin embargo, esto todavía significa que la devolución de llamada se programa después de que se destruya su fragmento y, debido a ello, su instancia fragmento se filtró. Lo mejor es crear un Handler y publicar el Runnable en lugar de llamar a runOnUiThread() . A continuación, en onDestroy() , llame a mHandler.removeCallbacksAndMessages(null) , que esencialmente elimina la cola, de modo que el Runnable no se llame en absoluto.

 mMessageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if(mListener != null){ mListener.onFragmentInteraction(0); } } }; 

Cuando la aplicación recibe difusión, puede ser que esta actividad se haya cerrado en ese momento

@Jschools tiene la mejor respuesta. Pero como alternativa también podría usar Eventbus en lugar del patrón de escucha. El evento sólo transmitirá el evento y si la actividad no está activa ningún evento llegará y no se lanzará NPE.

Según documentación onAttach se llama cuando un fragmento se adjunta primero a su contexto. Ahora que no está instanciando directamente el fragmento dentro de la actividad, sino a través del adaptador, ¿está seguro de que se está llamando al método onAttach (Context context) del DebugFragment porque es donde ha asignado el contexto al mListener?

Se han reportado casos donde no se llama al método onAttach (Context context). Consulta https://code.google.com/p/android/issues/detail?id=183358.

Omita los métodos del ciclo de vida Fragment todos juntos y establezca el derecho mListener en newInstance ().

 public static DebugFragment newInstance(Context context) { DebugFragment fragment = new DebugFragment(); fragment.setListener(context) Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } private void setListener(Context context){ if (context.instanceof(OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } 
  • ¿Por qué OnCreate () de Fragment se llama a veces antes de OnCreate de Activity ()?
  • DatePickerDialog onDateSet llamado cuando se gira
  • Realización de una parada de actividad que no se reanuda - Android
  • IllegalStateException: Fragmento ya agregado en el fragmento tabhost
  • ¿Cómo puedo guardar la pila trasera de la aplicación en un lote?
  • Cómo "destruir" varias actividades de Android al mismo tiempo
  • ¿Cuándo se llaman onSaveInstanceState () y onRestoreInstanceState (), exactamente?
  • LocalBroadcastManager y el ciclo de vida de la actividad
  • OnActivityCreated siempre se llama?
  • SavedInstanceState vs getIntent (). GetExtras ()
  • ¿Se llama ciclo de vida cuando se presiona la tecla de retroceso para volver a la actividad anterior?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.