Как получить представление фрагмента за пределами OnCreateView()
У меня есть Fragment с TableLayout. Данные в таблице взяты из базы данных SQLite. База данных SQLite заполняется из RESTful webservice в AsyncTask в MainActivity. Перед заполнением таблицы Fragment Необходимо дождаться завершения задачи. Fragment ожидает вызова метода task onPostExecute(). Когда это так, вызывается метод onLoadAndStoreComplete() в Fragment. Это все работает.
Мне нужно получить представление о TableLayout вне метода OnCreateView() фрагмента. Если бы я мог получить представление о фрагменте в onLoadAndStoreComplete это привело бы меня туда.
Тот же код, что и здесь.
Я получил mContext от MainActivity, но у этого нет метода getView(), связанного с ним.
Я пробовал:
- создание члена класса rootView и назначение в onCreateView (), но в onLoadAndStoreComplete(), он равен null.
- создание члена класса tableLayout и назначение в onCreateView (), но в onLoadAndStoreComplete(), это null.
- звоню сюда.getView () снова в onLoadAndStoreComplete(), но возвращает null.
- вызов инфлятора внутри onLoadAndStoreComplete(), что работает, но тогда я не знаю, что использовать для контейнера в вызове .inflate()
Я не понимаю, почему значения членов класса rootView и tableLayout равны нулю в onLoadAndStoreComplete()
public class MyFragment extends Fragment implements OnLoadAndStoreCompleteListener {
private TableLayout tableLayout;
private View rootView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mContext = this.getActivity();
rootView = inflater.inflate(R.layout.fragment_permits, container, false); // this works
tableLayout = (TableLayout) rootView.findViewById(R.id.main_table); // and this
...
}
@Override
public void onLoadAndStoreComplete() {
// rootView is null, ie not remembered from OnCreateView
View view = getView(); // null
LayoutInflater inflater = LayoutInflater.from(getActivity());
rootView = inflater.inflate(R.layout.fragment_permits, container, false); // container? don't know what it should be
// tableLayout is null
tableLayout.addView(tableRow, new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
}
...
}
6 ответов:
Если я правильно понимаю ваш код, то что-то не так либо с вашим кодом, не соответствующим жизненному циклу фрагмента, либо с отказом экземпляра другого фрагмента.
A. проблема жизненного цикла
Android framework ожидает, что ваш фрагмент создаст свое представление внутри метода
onCreateView(). Представление становится доступным после того, как фреймворк вызывает этот метод.Возможно, что ваш код вызвал
onLoadAndStoreComplete()раньшеonCreateView(), и это вызвало проблема.Вам нужно извлечь метод для заполнения фактических представлений данными, так как он может иметь 2 точки входа. Пожалуйста, смотрите код ниже:
public class MyFragment extends Fragment implements OnLoadAndStoreCompleteListener { private TableLayout tableLayout; private View rootView; private SomeDataClass loadedData; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mContext = this.getActivity(); rootView = inflater.inflate(R.layout.fragment_permits, container, false); tableLayout = (TableLayout) rootView.findViewById(R.id.main_table); updateUi(); // If onLoadAndStoreComplete() was already called // this will plug newly created view to returned data } @Override public void onLoadAndStoreComplete() { loadedData = ...; // Save loaded data here updateUi(); // If onCreateView() was already called // this will plug loaded data to the view } private void updateUi() { if (rootView == null) { // Check if view is already inflated return; } if (loadedData != null) { // View is already inflated and data is ready - update the view! ... } } }B. отказ другого экземпляра
Это может произойти, когда вы работаете с 2 различными экземплярами ранее упомянутого фрагмента.
Сначала все будет выглядеть по порядку:
onCreateView()вызывали раньшеonLoadAndStoreComplete(). Поэтому проверьте следующее:Если это то, что происходит, причина, вероятно, скрыта немного глубже, и без кода я не могу дать вам точный совет на этот счет. Как вы создаете свой фрагмент? Через XML или вручную, а затем добавление через FragmentManager или через Видоискатель?
- конструктор Log / debug по умолчанию вызывает ваш фрагмент. Вы ожидая получить один вызов для вашего фрагмента во время потока create / load.
- проверьте, является ли объект, который вызвал
onCreateView(), точно таким же объектом, который вызвалonLoadAndStoreComplete(), Вы можете использоватьSystem.identityHashCode(this), получение различных значений в рамках этих двух методов является плохим знаком
getView()дает rootView фрагмента, который возвращается изonCreatedView(). Таким образом, еслиonLoadAndStoreComplete()вызывается до того, какonCreatedView()будет завершен (что он не может вернуть ваш rootView), вы получитеnull, так как представление еще не создано.
Я попытался вызвать
getView()внутриonViewCreated(), который не является нулевым:@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); View viewer=getView(); if(viewer==null){ Itu.showToast("null",getActivity(), Toast.LENGTH_LONG); }else{ Itu.showToast(viewer.toString(),getActivity(), Toast.LENGTH_LONG);//This is called } }
Из вашего фрагмента кода, если поля
rootViewиtableLayoutинициализируются после вызоваonCreateView(..), если оба поля после этого не заданы в null, то они должны быть не null при вызовеonLoadAndStoreComplete(..).Сказал, что, я думаю, вы вызываете этот метод в другом экземпляре вашего фрагмента. Просмотрите код действия и убедитесь, что вы все время используете один и тот же экземпляр из фрагмента.
Мне нужно получить представление TableLayout за пределами OnCreateView() метод фрагмента. Если бы я мог получить представление о фрагменте в onLoadAndStoreComplete, который приведет меня туда.
Попробуйте изменить определение onLoadAndStoreComplete, чтобы получить представление, а затем передать представление фрагмента.
Вы уверены, что onLoadAndStoreComplete() вызывается после onCreateView()? Единственная причина, по которой переменные экземпляра имеют значение null, заключается в том, что метод, который их инициализирует, не вызывается.
Я предлагаю вам поставить вызов в журнал.D в onAttach, onDetach метод onCreate, onCreateView, методы onStart, то onStop,onLoadAndStoreComplete, чтобы увидеть, в каком порядке называются. После этого обновите свой вопрос с выводом журнала, чтобы увидеть, в чем может быть проблема, и, вероятно, я мог бы дать вам более краткий ответ. ответ.
Вы можете сделать несколько исправлений:
Если асинхронная задача вызывается до запуска фрагмента, то ваш обратный вызов onLoadAndStoreComplete может быть вызван до onCreateView (и все ваши представления не завышены)
Вы можете выполнить asyncTask из onCreateView, но вам нужно отобразить загрузчик, чтобы сообщить пользователю, что приложение синхронизируется
Вы также можете использовать listview, а не tableLayout:
public class MyFragment extends Fragment implements OnLoadAndStoreCompleteListener { private ListView listView; private View rootView; private MyAdapter adapter; private List<T> mDatas; /// This one is populated like you want, from onLoadAndStoreComplete @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mContext = this.getActivity(); rootView = inflater.inflate(R.layout.fragment_permits, container, false); // this works listView = (ListView) rootView.findViewById(R.id.main_table); // and this mDatas = new List<>(); adapter = new MyAdapter(); tableLayout.setAdapter(adapter); } @Override public void onLoadAndStoreComplete() { adapter.notifyDataSetChanged(); } private class MyAdapter extends BaseAdapter{ @Override public int getCount() { // TODO Auto-generated method stub return mDatas.size() == 0 ? 1 : mDatas.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return mDatas.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (mDatas.size()==0){ // inflate new view with only a progressbar indefinite LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.row_loading, parent, false); return convertView; } else{ // list is populated LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.row_datas, parent, false); // do inflating view stuff return convertView; } } }Вам нужно изменить свой tableLayout на ListView (внутри Относительный отказ?)
Comments