Loader calls onLoadFinished before Activity's onCreateOptionsMenu

When an AsynctaskLoader is initiated from Activity's OnCreate() , it finishes its work and calls onLoaderFinished() before action bar menu is inflated, that is before onCreateOptionsMenu() is called.

I need to alter some action menu items depending on results of loader. What approach might resolve this ?

UPDATE: This happens On orientation change. I'm Observing this sequence in debugger:

  • Application Start: onCreate() -> onCreateOptionsMenu() -> onLoadFinished()
  • Rotate to landscape: onCreate() -> onLoadFinished() -> onCreateOptionsMenu()
  • Rotate back to portrait: onCreate() -> onLoadFinished() -> onCreateOptionsMenu()

  • I ran into the same scenario when trying to call shareActionProvider.setShareIntent() in onLoadFinished() which was dependent on shareActionProvider being initalized in onCreateOptionsMenu() .

    My solution was to scope both my Intent and ShareActionProvider to the Fragment, and then within each method initialize the appropriate field and set the other if it had already been defined. That way it works no matter which is called first without invalidating the menu.

    Here's basically what it looks like

    public class myFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
    ...
    private ShareActionProvider shareActionProvider;
    private Intent shareIntent;
    ...
    

    onCreateOptionsMenu()

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_my_fragment, menu);
    
        MenuItem menuItem = menu.findItem(R.id.action_share);
        shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);
        //in the case where onLoadFinished is called first, simply set the share intent here.
        if (null != shareIntent)
        {
            shareActionProvider.setShareIntent(shareIntent);
        }
    }
    

    onLoadFinished()

    @Override
    public void onLoadFinished(android.support.v4.content.Loader<Cursor> loader, Cursor data) {
    
        ... <get some data from cursor> ...
    
        shareIntent = new Intent(Intent.ACTION_SEND);
        shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
        shareIntent.setType("text/plain");
        shareIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text)+data);
    
        //shareActionProvider may be null due to onLoadFinished called before onCreateOptionsMenu
        if (null != shareActionProvider)
        {
            shareActionProvider.setShareIntent(shareIntent);
        }
    

    I need to alter some action menu items depending on results of loader. What approach might resolve this ?

    Your scenarios #2 and #3 should be perfectly fine for you, then. By the time onCreateOptionsMenu() is called, you have your Cursor (or whatever) from your Loader and can tailor what you do in onCreateOptionsMenu() .

    With regards to scenario #1, have onCreateOptionsMenu() do the most likely thing, and if you determine in onLoadFinished() that this is incorrect, call invalidateOptionsMenu() to force another call to onCreateOptionsMenu() , I suppose.


    This particular approach avoids invalidating entire menu.

    Define one boolean flag, and one MenuItem variable for each item you want to control based on outcomes of loader results:

    Let's say you want to enable New action only if loader returns any success:

    private boolean mEnableNew = false;
    private MenuItem mItemNew;
    

    Save the menu item to variable when menu is created, also, apply state:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
      getMenuInflater().inflate(R.menu.manage_menu, menu);
    
      mItemNew = menu.findItem(R.id.itm__manage_menu__new);
      mItemNew.setEnabled(mEnableNew);
    
      return super.onCreateOptionsMenu(menu);
    }
    

    Finally, obtain new settings based on Loader's results, and enable disable menu item:

    @Override
    public void onLoadFinished(Loader<BI_Result> loader, Result result) {
    
        //--If onCreateOptionsMenu is not yet executed,it will use this boolean value when it does
        mEnableNew = result.isSuccess(); 
    
        //--If onCreateOptionsMenu has executed, we apply state here
        if (mItemNew != null) {
            mItemNew.setEnabled(mEnableNew);
        }
    }
    
    链接地址: http://www.djcxy.com/p/11208.html

    上一篇: 如何使用jQuery Mobile实现多列表?

    下一篇: 加载程序在Activity的onCreateOptionsMenu之前调用onLoadFinished