5

Я использую ViewPager из ACL, чтобы показать пару Fragment s. Сначала эти фрагменты, где все ListFragment s, поскольку они содержат список. Я пытаюсь имитировать таблицу с двумя столбцами, поэтому каждый элемент в списке содержит другой список из двух объектов. Я хочу, чтобы каждая ячейка была долгообходимой (не весь элемент списка), поэтому я реализовал свой собственный ColumnLayout (возможно, его следует назвать CellLayout). Каждый элемент списка содержит два столбца ColumnLayouts, которые являются long-clickable и реализуют getContextMenuInfo(), чтобы возвращать информацию об объекте с длинным кликом. Этот метод просматривает ViewPager, запрашивает текущий фрагмент, а затем вызывает фрагмент, чтобы вернуть идентификатор объекта из длинного щелчка. Чтобы получить правильную строку, необходимо сделать фрагмент:onCreateView не вызывается с фрагментом в ViewPager

getListView().getPositionForView(v) 

И вот где проблема. Иногда getListView() throws IllegalStateException говорят, что «Просмотр контента еще не создан». То есть onCreateView(...) не был вызван. Это происходит иногда, когда приложение возобновляется. Сегодня мне удалось повторно создать проблему, включив опцию «Не сохранять действия» в настройках> Параметры разработчика на моем Galaxy Nexus. Я запустил приложение, нажмите «Домой», а затем снова откройте приложение из меню последних приложений, и теперь, если я долгое время нажимаю любую из ячеек в своем списке, это исключение вызывается. По некоторым выводам отладки мне удалось проверить, что onCreateView никогда не вызывался. Что странно, потому что весь ViewPager с его фрагментом и его ListView и его элементы ячейки все нарисованы!

мне сказали на # андроид-разработчике, что ListFragment в ACL не поддерживает пользовательские макеты, так что я вновь реализованный мою android.support.v4.app.Fragment без использования ListFragment, но это не помогло.

Краткое резюме: У меня есть пользовательский макет, который обрабатывает событие долгого нажатия раскладку с целью создания MenuInfo объекта, содержащего информацию о entitiy в камере прессованного. Чтобы найти объект, содержащийся в макете, в конечном итоге вызывается listview.getPositionForView(View v), иногда вызывающий IllegalStateException.

Вот мой пользовательский макет (возможно, есть более простой способ заполучить ViewPager, чем копаться в иерархии вида):

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; 
     } 

    } 
} 

И вот (фрагмент) 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); 
    } 

Не странно ли, что при возобновлении приложения (если действие было уничтожено), ViewPager с его фрагментами и его ListView и его пользовательскими макетами нарисованы. Но я получаю IllegalStateException, говоря, что представление не было создано, если я долгое время нажимаю любую из ячеек в списке?

редактировать/ На самом деле, Log.d(Constants.TAG, "onCreateView!!!!"); выход в onCreateView показывает, что методы вызывается два раза первый раз, когда я запустить приложение (по одному для каждого фрагмента в ViewPager), но тогда он никогда не вызывается снова, когда приложение возобновляется! ? Это ошибка или что я могу сделать неправильно?

ответ

4

Важная часть, по-видимому, была FragmentPagerAdapter (в которую я не включил). Отладка показывает, что getItem() не вызывается при восстановлении активности. Фрагменты воссоздаются другими способами. Это означало, что моя реализация FragmentPagerAdapter имела неправильные ссылки на фрагменты в FragmentManager.

Так что, когда мне нужно найти фрагмент, я использую findFragmentByTag() (на FragmentManager), используя makeFragmentName(), чтобы получить соответствующее имя тега. Это метод, используемый FragmentPagerAdapter при добавлении фрагмента. Не уверен, что это безопасный подход или нет.

Смежные вопросы