фиксация фрагмента из onLoadFinished в рамках activity
У меня есть действие, которое загружает список данных с сервера, используя обратные вызовы загрузчика. Я должен перечислить данные в фрагмент, который расширяется
SherlockListFragment
Я попытался зафиксировать фрагмент с помощью
Fragment newFragment = CategoryFragment.newInstance(mStackLevel,categoryList);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.simple_fragment, newFragment).commit();
В onLoadFinished и это дает IllegalStateException говоря
java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished
Я привел пример в actionbar sherlock, но эти примеры имеют загрузчики внутри фрагментов, а не действия.
Может ли кто-нибудь помочь мне с этим o, чтобы я мог это исправить без вызова загрузчика из фрагмента!
3 ответа:
Атласт, я нашел решение этой проблемы. Создайте дескриптор, устанавливающий пустое сообщение, и вызовите этот обработчик onLoadFinished(). Код похож на этот.
@Override public void onLoadFinished(Loader<List<Station>> arg0, List<Station> arg1) { // do other actions handler.sendEmptyMessage(2); }
В обработчике,
private Handler handler = new Handler() { // handler for commiting fragment after data is loaded @Override public void handleMessage(Message msg) { if(msg.what == 2) { Log.d(TAG, "onload finished : handler called. setting the fragment."); // commit the fragment } } };
Количество фрагментов зависит от требования.
This method can be mainly used in case of stackFragments, where all fragments have different related functions.
Согласно документам Android по методу onLoadFinished ():
Обратите внимание, что обычно приложению не разрешается совершать фрагментарные транзакции во время этого вызова, так как это может произойти после сохранения состояния действия. Смотрите Раздел FragmentManager.openTransaction() для дальнейшего обсуждения этого вопроса.(Примечание: скопируйте / вставьте эту ссылку в ваш браузер... StackOverflow не справляется с этим хорошо..)
Таким образом, вы просто никогда не должны загружать фрагмент в этом состоянии. Если вы действительно не хотите помещать загрузчик во фрагмент, то вам нужно инициализировать фрагмент в вашем методе onCreate() действия, а затем, когда onLoadFinished произойдет, просто вызовите метод на вашем фрагменте.Некоторый грубый псевдокод выглядит следующим образом:
Очевидно, вы захотите использовать правильный объект.. и правильный загрузчик, и, вероятно, определить полезный метод setData() для обновления вашего фрагмента. Но, надеюсь, это укажет вам правильное направление.public class DummyFragment { public void setData(Object someObject) { //do stuff } public class DummyActivity extends LoaderCallbacks<Object> { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Fragment newFragment = DummyFragment.newInstance(); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.add(R.id.simple_fragment, newFragment).commit(); getSupportLoaderManager.initLoader(0, null, this) } // put your other LoaderCallbacks here... onCreateLoader() and onLoaderReset() public void onLoadFinished(Loader<Object> loader, Object result) { Fragment f = getSupportLoaderManager.findFragmentById(R.id.simple_fragment); f.setData(result); }
Как ответил @kwazi, это плохой пользовательский опыт для вызова
FragmentTransition.commit()
изonLoadFinished()
. Я нашел решение для этого события с помощью ProgressDialog.Впервые создан
ProgressDialog.setOnDismissListener(new listener)
для наблюдения заonLoadFinished().
Далее я делаюprogressDialog.show()
ПередgetLoaderManager().restartLoader()
. И в конце концов поместитьprogressDialog.dismiss()
вonLoadFinished()
. Такой подход позволяет не связывать основной поток пользовательского интерфейса и поток загрузчика.
public class FrPersonsListAnswer extends Fragment implements LoaderCallbacks<Cursor>{ private ProgressDialog progressDialog; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_persons_list, container, false); //prepare progress Dialog progressDialog = new ProgressDialog(curActivity); progressDialog.setMessage("Wait..."); progressDialog.setIndeterminate(true); progressDialog.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { //make FragmentTransaction.commit() here; //but it's recommended to pass control to your Activity //via an Interface and manage fragments there. } }); lv = (ListView) view.findViewById(R.id.lv_out1); lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) { //START PROGRESS DIALOG HERE progressDialog.show(); Cursor c = (Cursor) parent.getAdapter().getItem(position); // create Loader getLoaderManager().restartLoader(1, null, curFragment); } }); return view; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { switch (loader.getId()) { case 1: //dismiss dialog and call progressDialog.onDismiss() listener progressDialog.dismiss(); break; default: break; } }