Estoy usando ViewPager
desde la ACL para mostrar un par de Fragment
s. Al principio, estos Fragmentos son todos ListFragment
s ya que contienen una lista. Estoy tratando de imitar una tabla de 2 columnas, por lo que cada elemento en la lista contiene otra lista de dos objetos. Quiero que cada celda tenga un clic largo (no todo el elemento de la lista), por lo tanto implementé mi propio ColumnLayout (quizás debería llamarse CellLayout). Cada elemento de la lista contiene dos ColumnLayouts en los que se hace clic con el botón largo e implementa getContextMenuInfo()
para devolver información sobre la entidad a la que se hizo clic en forma prolongada. Este método busca el ViewPager, solicita el fragmento actual y luego llama al fragmento para devolver el id de la entidad de la vista en la que se hizo clic con el botón largo. Para obtener la fila correcta, el fragmento debe hacer:onCreateView no llamado con Fragment en ViewPager
getListView().getPositionForView(v)
Y aquí es donde comienza el problema. Algunas veces getListView()
lanza IllegalStateException
diciendo "Vista de contenido aún no creada". Es decir. onCreateView(...)
no ha sido llamado. Esto solo sucede a veces cuando la aplicación se reanuda. Hoy pude volver a producir el problema activando la opción "No mantener actividades" en Configuración> Opciones de desarrollador en mi Galaxy Nexus. Inicié la aplicación, presiono Inicio y luego volví a abrir la aplicación desde el menú de aplicaciones recientes y ahora, si hago un clic largo en cualquiera de las celdas de mi vista de lista, se lanza esta excepción. Por algunos resultados de depuración logré verificar que nunca se ha llamado a onCreateView. ¡Lo cual es un poco extraño porque todo el ViewPager con su Fragmento y su ListView y sus elementos de celda están dibujados!
me dijeron en # android-dev que ListFragment
en el ACL no es compatible con diseños personalizados, así que reimplementado mi android.support.v4.app.Fragment
sin utilizar ListFragment
pero eso no ayuda.
Breve resumen: Tengo un diseño personalizado que maneja el caso de una presión larga en el diseño con el fin de crear un MenuInfo
objeto que contiene información sobre entitiy en la celda presionado. Para encontrar la entidad contenida en el diseño, eventualmente se llama listview.getPositionForView(View v)
, lo que a veces causa un IllegalStateException
.
Aquí mi diseño personalizado (tal vez hay una manera más fácil controlar la ViewPager
que cavar en la jerarquía de vistas):
package org.remotestick;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View;
import android.widget.LinearLayout;
public class ColumnLayout extends LinearLayout {
public ColumnLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ColumnLayout(Context context) {
super(context);
}
@Override
protected ContextMenuInfo getContextMenuInfo() {
int itemTypeId = getChildAt(0).getId();
int positionTypeId = getId();
View currentView = this;
ViewPager viewPager = null;
while(currentView.getParent() != null) {
currentView = (View) currentView.getParent();
if(currentView.getId() == R.id.pager) {
viewPager = (ViewPager) currentView;
break;
} else if (currentView.getId() == R.id.rootLayout)
break;
}
if(viewPager == null)
return null;
WorkspaceAdapter adapter = (WorkspaceAdapter) viewPager.getAdapter();
Pair<Integer, Integer> itemIdAndListPosition = adapter.getItemIdFromWorkspace(viewPager.getCurrentItem(), this, itemTypeId, (positionTypeId == R.id.leftColumn));
if(itemIdAndListPosition == null)
return null;
else
return new MatrixAdaptableContextMenuInfo(itemTypeId, itemIdAndListPosition.first, itemIdAndListPosition.second);
}
public static class MatrixAdaptableContextMenuInfo implements ContextMenuInfo {
public final int itemTypeId;
public final Integer itemId;
public final Integer positionInList;
public MatrixAdaptableContextMenuInfo(int itemTypeId, Integer itemId, Integer positionInList) {
this.itemTypeId = itemTypeId;
this.itemId = itemId;
this.positionInList = positionInList;
}
}
}
Y aquí está (un fragmento de) la Fragment
:
public class EntityTableFragment extends Fragment implements TelldusEntityChangeListener {
protected static final String ARG_TITLE = "title";
protected MatrixAdapter mAdapter;
protected ProgressViewer mProgressViewer;
protected MatrixFilter mFilter;
protected Handler mHandler = new Handler();
protected RemoteStickData db;
public boolean onAttach = false;
public boolean onCreateView = false;
private ListView listView;
public static EntityTableFragment newInstance(String title) {
EntityTableFragment f = new EntityTableFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
f.setArguments(args);
return f;
}
@Override
public void onAttach(SupportActivity activity) {
super.onAttach(activity);
onAttach = true;
try {
mProgressViewer = (ProgressViewer) activity;
mAdapter = new MatrixAdapter(getActivity(), mProgressViewer, new ArrayList<List<MatrixEntity>>(), null);
TelldusLiveService.addListener(this);
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement ProgressViewer");
}
db = new RemoteStickData(getActivity());
}
@Override
public void onDetach() {
super.onDetach();
TelldusLiveService.removeListener(this);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView.setAdapter(mAdapter);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list, null);
listView = (ListView) view.findViewById(R.id.list);
return view;
}
@Override
public String toString() {
return getArguments().getString(ARG_TITLE);
}
public Pair<Integer, Integer> getIdAndPositionForView(View v, boolean isLeft) {
if(listView == null)
throw new IllegalStateException("Listview not yet created");
int positionForView = listView.getPositionForView(v);
if(isLeft)
return new Pair<Integer, Integer>(mAdapter.getItem(positionForView).get(0).getId(), positionForView);
else
return new Pair<Integer, Integer>(mAdapter.getItem(positionForView).get(1).getId(), positionForView);
}
¿No es extraño que, al reanudar la aplicación (si se destruyó la actividad), se dibujan ViewPager con sus Fragmentos y su ListView y sus diseños personalizados? Sin embargo, recibo IllegalStateException
diciendo que la vista no se ha creado si presiona largamente alguna de las celdas en la vista de lista?
editar/ En realidad, una salida Log.d(Constants.TAG, "onCreateView!!!!");
en onCreateView
muestra que los métodos se invocan dos veces la primera vez que se inicia la aplicación (una para cada fragmento en el ViewPager), pero luego nunca es llamado de nuevo cuando se reanude la aplicación! ? ¿Es eso un error o qué podría estar haciendo mal?