Фиксировать фрагмент из onLoadFinished в действии

У меня есть активность, которая загружает список данных с сервера с помощью обратных вызовов загрузчика. Я должен перечислить данные в фрагмент, который расширяет

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

Я привел пример в sbarlock, но эти примеры содержат загрузчики внутри фрагментов, а не активность.

Может кто-нибудь помочь мне с этим o, что я могу исправить это, не вызывая загрузчик из фрагмента!

Ответ 1

Atlast, я нашел решение этой проблемы. Создайте дескриптор, установив пустое сообщение, и вызовите этот обработчик 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.

Ответ 2

В соответствии с документами Android по методу onLoadFinished():

Обратите внимание, что обычно приложению не разрешается совершать транзакции фрагментов во время этого вызова, так как это может произойти после сохранения состояния активности. См. FragmentManager.openTransaction() для дальнейшего обсуждения этого вопроса.

https://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoadFinished (android.content.Loader, D)

(Примечание: скопируйте/вставьте эту ссылку в свой браузер... StackOverflow не справляется с этим хорошо.)

Таким образом, вы просто не должны загружать фрагмент в этом состоянии. Если вы действительно не хотите помещать Loader во Фрагмент, тогда вам нужно инициализировать фрагмент в вашем методе onCreate() Activity, а затем, когда onLoadFinished происходит, просто вызовите метод на вашем фрагменте.

Ниже приведен псевдо-код грубого:

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

Очевидно, что вы захотите использовать правильный объект.. и правый загрузчик и, вероятно, определите полезный метод setData() для обновления вашего фрагмента. Но, надеюсь, это укажет вам в правильном направлении.

Ответ 3

Как @kwazi ответил, что это плохой пользовательский интерфейс, чтобы вызвать FragmentTransition.commit() из onLoadFinished(). Я нашел решение для этого события, используя ProgressDialog.

Сначала созданный ProgressDialog.setOnDismissListener(new listener) для просмотра onLoadFinished(). Далее я делаю progressDialog.show() до getLoaderManager().restartLoader(). И в конечном итоге поместите progressDialog.dismiss() в onLoadFinished(). Такой подход позволяет не связывать основной поток пользовательского интерфейса и поток Loader.

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