onCreateView не вызывается с фрагментом в ViewPager - PullRequest
5 голосов
/ 17 января 2012

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

getListView().getPositionForView(v)

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

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

Краткое резюме: У меня есть пользовательский макет, который обрабатывает событие длительного нажатия на макет дляцель создания MenuInfo объекта, содержащего информацию о правах в нажатой ячейке.Чтобы найти сущность, содержащуюся в макете, в конечном итоге вызывается 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, говоря, что представление не было создано, если я долго нажимаю на любую из ячеек в просмотре списка?

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

Ответы [ 2 ]

4 голосов
/ 19 января 2012

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

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

0 голосов
/ 26 февраля 2019

Лучше использовать FragmentStatePagerAdapter , чтобы фрагменты создавались соответствующим образом.

...