11

ローダーコールバックを使用してサーバーからデータリストを読み込むアクティビティがあります。データを拡張するフラグメントにリストする必要があります

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

アクションバーのシャーロックで例を参照しましたが、これらの例では、アクティビティではなくフラグメント内にローダーがあります。

フラグメントからローダーを呼び出さなくても修正できるように、誰かがこれを手伝ってくれますか?

4

3 に答える 3

14

最後に、この問題の解決策を見つけました。空のメッセージを設定するハンドルを作成し、そのハンドラ 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.
于 2012-09-14T09:17:41.813 に答える
8

onLoadFinished() メソッドの Android ドキュメントに従って:

アクティビティの状態が保存された後に発生する可能性があるため、通常、この呼び出し中にアプリケーションがフラグメント トランザクションをコミットすることは許可されていないことに注意してください。詳細については FragmentManager.openTransaction() を参照してください。

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

(注:そのリンクをコピーしてブラウザに貼り付けてください... StackOverflowはそれをうまく処理していません..)

したがって、その状態でフラ​​グメントをロードするべきではありません。ローダーをフラグメントに配置したくない場合は、アクティビティの onCreate() メソッドでフラグメントを初期化し、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() メソッドを定義してフラグメントを更新したいと思うでしょう。しかし、うまくいけば、これはあなたを正しい方向に向けるでしょう.

于 2012-09-07T16:36:40.790 に答える
0

@kwaziが答えたように、これはから呼び出すには悪いユーザーエクスペリエンスFragmentTransition.commit()ですonLoadFinished()。ProgressDialog を使用して、このイベントの解決策を見つけました。

最初は、 私が以前にProgressDialog.setOnDismissListener(new listener)行った詳細を見るために作成されました。そして最終的に に配置します。このようなアプローチでは、メインの UI スレッドとローダーのスレッドをバインドしません。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;
		}
	}

于 2015-03-20T11:25:40.623 に答える