私はこのようにアプリを作りました:
ViewPager で DrawerLayout を実装しようとしています。DrawerLayout からアイテムを選択すると、メソッドに入り、getItem()
選択した位置に応じて Fragment または別のメソッドが呼び出されます。
この Fragment では、ViewPager が作成およびビルドされます。
私の場合、ViewPager には 3 つの Fragment が含まれています。
最初の 3 つの Fargments は問題なくビルドされ、正しく表示されます。パフォーマンスを向上させるためにすべてがキャッシュされていると思います。
今私は私の問題にコメントします:
DrawerLayout で同じアイテムを選択したり、別のアイテムから取得したり、同じものをクリックしたりすると、問題が発生します。
どうやら、以前に Fragments が作成され、キャッシュに格納され、現在はコンストラクターに入っていないようです。
LogCat で次のエラーが表示されます。
FATAL EXCEPTION: main
java.lang.NullPointerException
at android.support.v4.app.Fragment.setUserVisibleHint(Fragment.java:819)
at android.support.v4.app.FragmentStatePagerAdapter.setPrimaryItem(FragmentStatePagerAdapter.java:152)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1066)
at android.support.v4.view.ViewPager.populate(ViewPager.java:914)
at android.support.v4.view.ViewPager$3.run(ViewPager.java:244)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
at android.view.Choreographer.doCallbacks(Choreographer.java:562)
at android.view.Choreographer.doFrame(Choreographer.java:531)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
なぜこの問題が?どうすれば解決策を見つけることができますか?
私のコード:
MainActivity.java
package com.android.projects.elprogramademano;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
/**
* Clase MainActivity (mainActivity.xml).
*/
public class MainActivity extends FragmentActivity {
// Declarar variables
private DrawerLayout drawerLayout;
private ListView listViewSecciones;
private ActionBarDrawerToggle actionBarDrawerToggle;
private ConstructorListaSecciones listaSecciones;
private CharSequence tituloCajon;
private CharSequence titulo;
private String[] titulosSecciones;
private int[] iconosSecciones;
private Drawable oldBackground = null;
private int colorFondoActionBar;
private final Handler handler = new Handler();
private FragmentoActosYCultos fragmentoActosYCultos = new FragmentoActosYCultos();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Establecer el titulo de la barra de acciones
titulo = tituloCajon = getTitle();
// Cambiar el color de la barra de acciones
colorFondoActionBar = Constantes.COLOR_FONDO_ACTIONBAR;
cambiarColorBarraAcciones(colorFondoActionBar);
// Preparar el cajón de navegación
prepararCajonNavegacion();
if (savedInstanceState == null) {
selectItem(0);
}
}
/**
* Método que se encarga de preparar el cajón de navegación.
*/
private void prepararCajonNavegacion() {
// Generar los títulos de los secciones del cajón de navegación
titulosSecciones = getResources().getStringArray(R.array.secciones);
// Generar los iconos de los secciones del cajón de navegación
// iconosSecciones = new int[] { R.drawable.collections_cloud, R.drawable.collections_cloud, R.drawable.collections_cloud };
// Localizar DrawerLayout en activity_main.xml
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
// Localizar ListView in activity_main.xml
listViewSecciones = (ListView) findViewById(R.id.left_drawer);
// Establecer una sombra personalizado que se superpone a la página principal cuando el cajón se abre
drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// Pasar resultados a ConstructorListaSecciones.class
listaSecciones = new ConstructorListaSecciones(this, titulosSecciones, iconosSecciones);
// Establecer los ConstructorListaSecciones al ListView
listViewSecciones.setAdapter(listaSecciones);
// Capturar cuando se hace click sobre un sección del cajón de navegación
listViewSecciones.setOnItemClickListener(new DrawerItemClickListener());
// Habilitar el icono de la barra de acciones para que se comporte como una acción
getActionBar().setHomeButtonEnabled(true);
getActionBar().setDisplayHomeAsUpEnabled(true);
// Lazos ActionBarDrawerToggle junto a los de las interacciones apropiadas
// Entre el cajón deslizante y la barra de iconos App acción
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
public void onDrawerClosed(View view) {
// Cuando el cajón de navegación se cierra
super.onDrawerClosed(view);
getActionBar().setTitle(titulo);
}
public void onDrawerOpened(View drawerView) {
// Cuando el cajón de navegación se abre
super.onDrawerOpened(drawerView);
getActionBar().setTitle(tituloCajon);
}
};
// Establecer el ActionBarDrawerToggle al DrawerLayout
drawerLayout.setDrawerListener(actionBarDrawerToggle);
}
@Override
public void setTitle(CharSequence title) {
titulo = title;
getActionBar().setTitle(titulo);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
if (drawerLayout.isDrawerOpen(listViewSecciones)) {
drawerLayout.closeDrawer(listViewSecciones);
} else {
drawerLayout.openDrawer(listViewSecciones);
}
}
return super.onOptionsItemSelected(item);
}
/**
* Clase DrawerItemClickListener.
*/
private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
/**
* Metodo encargado de recuperar el sección seleccionado del cajón de navegación.
* @param position int
*/
private void selectItem(int position) {
// Localizar la posición
switch (position) {
case 0:
// Establezco el icono de la sección
// getActionBar().setIcon(R.drawable.ic_launcher_actionbar);
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragmentoActosYCultos).commit();
break;
case 1:
// Establezco el icono de la sección
// getActionBar().setIcon(R.drawable.ic_launcher_actionbar);
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragmentoActosYCultos).commit();
break;
case 2:
// Establezco el icono de la sección
// getActionBar().setIcon(R.drawable.ic_launcher_actionbar);
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, fragmentoActosYCultos).commit();
break;
}
// Establecer como marcado
listViewSecciones.setItemChecked(position, true);
// Establecer el titulo del sección en la barra de acciones
setTitle(titulosSecciones[position]);
// Cierre el cajón
drawerLayout.closeDrawer(listViewSecciones);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sincronizar el estado de alternancia después de producirse onRestoreInstanceState.
actionBarDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pasar cualquier cambio en la configuración de las palancas del cajón
actionBarDrawerToggle.onConfigurationChanged(newConfig);
}
/**
* Método encargado de cambiar el color de la barra de acciones.
* @param color int
*/
private void cambiarColorBarraAcciones(int color) {
// Cambiamos de color el ActionBar solo si existe alguno disponible.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
Drawable colorDrawable = new ColorDrawable(color);
Drawable bottomDrawable = getResources().getDrawable(R.drawable.actionbar_bottom);
LayerDrawable ld = new LayerDrawable(new Drawable[] { colorDrawable, bottomDrawable });
if (oldBackground == null) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
ld.setCallback(drawableCallback);
} else {
getActionBar().setBackgroundDrawable(ld);
}
} else {
TransitionDrawable td = new TransitionDrawable(new Drawable[] { oldBackground, ld });
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
td.setCallback(drawableCallback);
} else {
getActionBar().setBackgroundDrawable(td);
}
td.startTransition(200);
}
oldBackground = ld;
getActionBar().setDisplayShowTitleEnabled(false);
getActionBar().setDisplayShowTitleEnabled(true);
}
colorFondoActionBar = color;
}
/**
* Método que se ejecuta al pulsar sobre un color del layout.
* @param view View
*/
public void onColorClicked(View view) {
// Recuperamos el color pasado por el Tag desde el componente del layout.
int color = Color.parseColor(view.getTag().toString());
// Cambiamos el color de la barra de acciones al color recuperado.
cambiarColorBarraAcciones(color);
}
private Drawable.Callback drawableCallback = new Drawable.Callback() {
@Override
public void invalidateDrawable(Drawable who) {
getActionBar().setBackgroundDrawable(who);
}
@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
handler.postAtTime(what, when);
}
@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
handler.removeCallbacks(what);
}
};
}
FragmentoActosYCultos.java
package com.android.projects.elprogramademano;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.libraries.pagerslidingtabstrip.PagerSlidingTabStrip;
/**
* Clase FragmentoActosYCultos (actos_y_cultos.xml).
*/
public class FragmentoActosYCultos extends Fragment {
// Declarar variables
private View viewActosYCultos;
private ViewPager viewPagerActosYCultos;
private PagerSlidingTabStrip pagerSlidingTabStripActosYCultos;
private ConstructorFragmentos fragmentPagerAdapterActosYCultos;
private String[] titulosTabs;
private int colorFondoPagerSlidingTabStrip;
private int colorIndicadorPagerSlidingTabStrip;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Localizar el layout
viewActosYCultos = inflater.inflate(R.layout.actos_y_cultos, container, false);
// Localizar ViewPager en actos_y_cultos.xml
viewPagerActosYCultos = (ViewPager) viewActosYCultos.findViewById(R.id.viewPagerActosYCultos);
// Localizar PagerSlidingTabStrip en actos_y_cultos.xml
pagerSlidingTabStripActosYCultos = (PagerSlidingTabStrip) viewActosYCultos.findViewById(R.id.pagerTabSlidingStripActosYCultos);
// Construir el ConstructorFragmentos
titulosTabs = getResources().getStringArray(R.array.dias);
fragmentPagerAdapterActosYCultos = new ConstructorFragmentos(getFragmentManager(), Constantes.ACTOS_Y_CULTOS, titulosTabs);
// Establecer el ConstructorFragmentos al ViewPager
viewPagerActosYCultos.setAdapter(fragmentPagerAdapterActosYCultos);
// Establecer los margenes al ViewPager
final int pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
viewPagerActosYCultos.setPageMargin(pageMargin);
// Establecer el ViewPager al PagerSlidingTabStrip
pagerSlidingTabStripActosYCultos.setViewPager(viewPagerActosYCultos);
// Establecer color al fondo del PagerSlidingTabStrip
colorFondoPagerSlidingTabStrip = Constantes.COLOR_FONDO_PAGER_SLIDING_TAB_STRIP;
pagerSlidingTabStripActosYCultos.setBackgroundColor(colorFondoPagerSlidingTabStrip);
// Establecer color al indicador del PagerSlidingTabStrip
colorIndicadorPagerSlidingTabStrip = Constantes.COLOR_FONDO_ACTIONBAR;
pagerSlidingTabStripActosYCultos.setIndicatorColor(colorIndicadorPagerSlidingTabStrip);
return viewActosYCultos;
}
}
コンストラクタFragmentos.java
package com.android.projects.elprogramademano;
import java.util.Locale;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.view.ViewGroup;
/**
* Clase ConstructorFragmentos.
*/
public class ConstructorFragmentos extends FragmentStatePagerAdapter {
// Declarar variables
private String activity;
private String[] titulosTabs;
/**
* Constructor de la clase.
* @param fm FragmentManager
* @param act String
* @param titulosTabs String[]
*/
public ConstructorFragmentos(FragmentManager fm, String act, String[] titulosTabs) {
super(fm);
// Recuperamos los parámetros.
activity = act;
this.titulosTabs = titulosTabs;
}
/*
* Método encargado de recuperar el titulo del Tab actual.
*/
@Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
return titulosTabs[position].toUpperCase(l);
}
/*
* Método encargado de recuperar el total de Tabs.
*/
@Override
public int getCount() {
return titulosTabs.length;
}
/*
* Método encargado de construir los fragmentos del layout actual.
*/
@Override
public Fragment getItem(int position) {
Fragment fragment = new Fragment();
if (activity != null && !activity.isEmpty()) {
// Si la actividad no es nula ni está vacía.
if (activity.equals(Constantes.PROCESIONES)) {
// Si es PROCESIONES.
fragment = ConstructorFragmentosProcesiones.newInstance(position);
} else if (activity.equals(Constantes.ACTOS_Y_CULTOS)){
// Si es ACTOSYCULTOS.
fragment = ConstructorFragmentosActosYCultos.newInstance(position);
}
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
@Override
public Object instantiateItem(ViewGroup arg0, int arg1) {
return super.instantiateItem(arg0, arg1);
}
@Override
public int getItemPosition(Object object) {
return super.getItemPosition(object);
}
}
コンストラクタFragmentosActosYCultos.java
package com.android.projects.elprogramademano;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.FrameLayout.LayoutParams;
import android.widget.Toast;
/**
* Clase ConstructorFragmentosActosYCultos.
*/
public class ConstructorFragmentosActosYCultos extends Fragment {
// Declarar variables
private static final String ARG_POSITION = "position";
private int position;
/**
* Constructor de la clase.
* @param position int
* @return ConstructorFragmentosActosYCultos
*/
public static ConstructorFragmentosActosYCultos newInstance(int position) {
ConstructorFragmentosActosYCultos f = new ConstructorFragmentosActosYCultos();
Bundle b = new Bundle();
b.putInt(ARG_POSITION, position);
f.setArguments(b);
return f;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
position = getArguments().getInt(ARG_POSITION);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LayoutParams params = new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout fl = new FrameLayout(getActivity());
fl.setLayoutParams(params);
final int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
TextView v = new TextView(getActivity());
params.setMargins(margin, margin, margin, margin);
v.setLayoutParams(params);
v.setGravity(Gravity.CENTER);
v.setBackgroundResource(R.drawable.background_card);
v.setText("ACTOS Y CULTOS " + (position + 1));
fl.addView(v);
fl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getActivity(), "PULSADO ACTOS Y CULTOS " + (position + 1), Toast.LENGTH_SHORT).show();
}
});
return fl;
}
}