En los informes de errores de la consola del desarrollador, a veces veo informes con problemas de NPE. No entiendo lo que está mal con mi código. En el emulador y la aplicación de mi dispositivo funciona bien sin cierres forzados, sin embargo, algunos usuarios obtienen NullPointerException en la clase de fragmento cuando se llama al método getActivity ().
Actividad
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) {}
});
}
Clase AsyncTask
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
Clase de fragmento
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();
...
}
}
Tal vez este error ocurre cuando las aplicaciones se reanudaron desde el fondo. En este caso, ¿cómo debo manejar esta situación correctamente?
Respuestas:
Parece que encontré una solución a mi problema. Muy buenas explicaciones se dan aquí y aquí . Aquí está mi ejemplo:
La idea principal de este código es que, mientras ejecuta su aplicación normalmente, crea nuevos fragmentos y los pasa al adaptador. Cuando reanude su administrador de fragmentos de aplicaciones ya tiene la instancia de este fragmento y necesita obtenerlo del administrador de fragmentos y pasarlo al adaptador.
ACTUALIZAR
Además, es una buena práctica usar fragmentos para verificar isAdded antes de llamar a getActivity (). Esto ayuda a evitar una excepción de puntero nulo cuando el fragmento se separa de la actividad. Por ejemplo, una actividad podría contener un fragmento que empuja una tarea asíncrona. Cuando finaliza la tarea, se llama al oyente onTaskComplete.
Si abrimos el fragmento, empujamos una tarea y luego presionamos rápidamente para regresar a una actividad anterior, cuando la tarea haya finalizado, intentará acceder a la actividad en onPostExecute () llamando al método getActivity (). Si la actividad ya está separada y esta verificación no está allí:
entonces la aplicación se bloquea.
fuente
isAdded()
antes de cada acceso ... hace que el código sea feo.if(isAdded())
oif(getActivity() != null)
Ok, sé que esta pregunta está realmente resuelta, pero decidí compartir mi solución para esto. He creado una clase padre abstracta para mi
Fragment
:Como puede ver, he agregado un oyente, así que cada vez que necesite obtener en
Fragments
Activity
lugar de estándargetActivity()
, necesitaré llamarfuente
Lo mejor para deshacerse de esto es mantener la referencia de actividad cuando
onAttach
se llama y usar la referencia de actividad donde sea necesario, por ejemploEditado, ya que
onAttach(Activity)
se deprecia y ahoraonAttach(Context)
se está utilizandofuente
getActivity()
devuelve nulo, es porque ya no estás en una actividad. Esta es una solución sucia.No llame a métodos dentro del Fragmento que requieran getActivity () hasta que se inicie en la Actividad principal.
fuente
He estado luchando contra este tipo de problema. por un tiempo, y creo que he encontrado una solución confiable.
Es bastante difícil saber con certeza que
this.getActivity()
no va a volvernull
por unFragment
, especialmente si está lidiando con algún tipo de comportamiento de red que le da a su código suficiente tiempo para retirarseActivity
referencias.En la solución a continuación, declaro una pequeña clase de administración llamada
ActivityBuffer
. Esencialmente, estoclass
trata de mantener una referencia confiable a un propietarioActivity
y promete ejecutarRunnable
s dentro de unActivity
contexto válido siempre que haya una referencia válida disponible. LosRunnable
s están programados para su ejecución en el subproceso de la interfaz de usuario inmediatamente siContext
está disponible; de lo contrario, la ejecución se aplaza hasta queContext
esté lista.En términos de su implementación, debemos tener cuidado de aplicar los métodos del ciclo de vida para que coincidan con el comportamiento descrito anteriormente por Pawan M :
Finalmente, en cualquier área dentro de su área
Fragment
que se extienda yBaseFragment
que no sea confiable para una llamadagetActivity()
, simplemente haga una llamadathis.getActivityBuffer().safely(...)
y declare unActivityBuffer.IRunnable
para la tarea!El contenido de su
void run(final Activity pActivity)
se garantiza que se ejecutará a lo largo del hilo de la interfaz de usuario.La
ActivityBuffer
continuación, se puede utilizar como sigue:fuente
fuente
Sé que esta es una pregunta antigua, pero creo que debo proporcionar mi respuesta porque otros no resolvieron mi problema.
en primer lugar: estaba agregando fragmentos dinámicamente usando fragmentTransactions. Segundo: mis fragmentos fueron modificados usando AsyncTasks (consultas DB en un servidor). Tercero: mi fragmento no fue instanciado al inicio de la actividad Cuarto: utilicé una instanciación de fragmento personalizada "crear o cargar" para obtener la variable del fragmento. Cuarto: la actividad se recreó debido al cambio de orientación
El problema era que quería "eliminar" el fragmento debido a la respuesta de la consulta, pero el fragmento se creó incorrectamente justo antes. No sé por qué, probablemente debido a la "confirmación" que se realizará más tarde, el fragmento aún no se agregó cuando llegó el momento de eliminarlo. Por lo tanto, getActivity () estaba devolviendo nulo.
Solución: 1) Tuve que verificar que estaba tratando de encontrar correctamente la primera instancia del fragmento antes de crear uno nuevo 2) Tuve que poner serRetainInstance (true) en ese fragmento para mantenerlo a través del cambio de orientación (sin apilamiento) por lo tanto, no es necesario ningún problema) 3) En lugar de "recrear o recuperar un fragmento viejo" justo antes de "eliminarlo", puse directamente el fragmento al inicio de la actividad. Crear una instancia al inicio de la actividad en lugar de "cargar" (o crear instancias) la variable de fragmento antes de eliminarla evitó problemas de getActivity.
fuente
En Kotlin puede intentar de esta manera manejar la condición nula getActivity ().
Verificará que la actividad sea nula o no y, si no es nula, ejecutará el código interno.
fuente