title: Should we really call getLoaderManager().initLoader in onActivityCreated, which causes onLoadFinished being called twice
body: <p>Google recommends us to call <code>getLoaderManager().initLoader(0, null, this);</code> within Fragment's <code>onActivityCreated</code></p>
  
  <p><a href="http://developer.android.com/reference/android/content/AsyncTaskLoader.html" rel="nofollow noreferrer">http://developer.android.com/reference/android/content/AsyncTaskLoader.html</a></p>
  
  <p>However, that yields the following problem : <strong>onLoadFinished will be called twice during configuration changes (Rotation)</strong></p>
  
  <p>We can simulate the problem as follow.</p>
  
  <h2>Code</h2>
  
  <pre><code>package org.yccheok.gui;
  
  import android.content.Context;
  import android.os.Bundle;
  import android.support.v4.app.LoaderManager;
  import android.support.v4.content.AsyncTaskLoader;
  import android.support.v4.content.Loader;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  
  import com.actionbarsherlock.app.SherlockFragment;
  
  public class HomeMenuFragment extends SherlockFragment implements LoaderManager.LoaderCallbacks&lt;HomeMenuFragment.Infos&gt; {
      private static class InfosLoader extends AsyncTaskLoader&lt;Infos&gt; {
  
          private Infos infos = null;
  
          public InfosLoader(Context context) {
              super(context);
          }
  
          @Override
          public Infos loadInBackground() {
              Log.i(TAG, "loadInBackground");
  
              this.infos = Infos.newInstance();
              return infos;
          }
  
          /**
           * Handles a request to cancel a load.
           */
          @Override 
          public void onCanceled(Infos infos) {
              super.onCanceled(infos);
          }
  
          /**
           * Handles a request to stop the Loader.
           * Automatically called by LoaderManager via stopLoading.
           */
          @Override 
          protected void onStopLoading() {
              // Attempt to cancel the current load task if possible.
              cancelLoad();
          }
  
          /**
           * Handles a request to start the Loader.
           * Automatically called by LoaderManager via startLoading.
           */
          @Override        
          protected void onStartLoading() {
              if (this.infos != null) {
                  Log.i(TAG, "deliverResult");
                  deliverResult(this.infos);
              }
  
              if (takeContentChanged() || this.infos == null) {
                  Log.i(TAG, "forceLoad");
                  forceLoad();
              }
          }
  
          /**
           * Handles a request to completely reset the Loader.
           * Automatically called by LoaderManager via reset.
           */
          @Override 
          protected void onReset() {
              super.onReset();
  
              // Ensure the loader is stopped
              onStopLoading();
  
              // At this point we can release the resources associated with 'apps'
              // if needed.
              this.infos = null;
          }        
      }
  
      static class Infos {
  
          private Infos() {
          }
  
          public static Infos newInstance() {
              return new Infos();
          }
      }
  
      @Override
      public void onActivityCreated (Bundle savedInstanceState) {
          super.onActivityCreated(savedInstanceState);
          Log.i(TAG, "onActivityCreated");
          // Prepare the loader.  Either re-connect with an existing one,
          // or start a new one.
          getLoaderManager().initLoader(0, null, this);
      }
  
      @Override
      public Loader&lt;Infos&gt; onCreateLoader(int arg0, Bundle arg1) {
          return new InfosLoader(this.getSherlockActivity());
      }
  
      @Override
      public void onLoadFinished(Loader&lt;Infos&gt; arg0, Infos arg1) {
          Log.i(TAG, "onLoadFinished! -&gt; " + arg1);
      }
  
      @Override
      public void onLoaderReset(Loader&lt;Infos&gt; arg0) {
      }
  
      public void reloadAfterOpenFromCloud() {
          this.getLoaderManager().getLoader(0).onContentChanged();
      }
  
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
              Bundle savedInstanceState) {
          View v = inflater.inflate(R.layout.home_menu, container, false);
          return v;
      }
  
      private static final String TAG = HomeMenuFragment.class.getSimpleName();
  }
  </code></pre>
  
  <h2>Logging</h2>
  
  <pre><code>I/HomeMenuFragment(14776): onActivityCreated
  I/HomeMenuFragment(14776): forceLoad
  I/HomeMenuFragment(14776): loadInBackground
  I/HomeMenuFragment(14776): onLoadFinished! -&gt; org.yccheok.gui.HomeMenuFragment$Infos@4195ad58
  
  [Rotation happens right here]
  
  I/HomeMenuFragment(14776): onActivityCreated
  I/HomeMenuFragment(14776): onLoadFinished! -&gt; org.yccheok.gui.HomeMenuFragment$Infos@4195ad58
  I/HomeMenuFragment(14776): onLoadFinished! -&gt; org.yccheok.gui.HomeMenuFragment$Infos@4195ad58
  </code></pre>
  
  <p>According to <a href="https://stackoverflow.com/questions/11293441/android-loadercallbacks-onloadfinished-called-twice">Android: LoaderCallbacks.OnLoadFinished called twice</a>, one of the proposed solution is calling <code>initLoader</code> in <code>onResume</code>.</p>
  
  <pre><code>@Override
  public void onActivityCreated (Bundle savedInstanceState) {
      super.onActivityCreated(savedInstanceState);
      Log.i(TAG, "onActivityCreated");
      //getLoaderManager().initLoader(0, null, this);
  }
  
  @Override
  public void onResume()
  {
      super.onResume();
      Log.i(TAG, "onResume");
      // Prepare the loader.  Either re-connect with an existing one,
      // or start a new one.
      getLoaderManager().initLoader(0, null, this);
  }
  </code></pre>
  
  <p>Here is the logging. It looks <strong>OK</strong> now after we move <code>initLoader</code> to <code>onResume</code>.</p>
  
  <h2>Logging</h2>
  
  <pre><code>I/HomeMenuFragment(15468): onActivityCreated
  I/HomeMenuFragment(15468): onResume
  I/HomeMenuFragment(15468): forceLoad
  I/HomeMenuFragment(15468): loadInBackground
  I/HomeMenuFragment(15468): onLoadFinished! -&gt; org.yccheok.gui.HomeMenuFragment$Infos@4195aed0
  
  
  I/HomeMenuFragment(15468): onActivityCreated
  I/HomeMenuFragment(15468): onResume
  I/HomeMenuFragment(15468): onLoadFinished! -&gt; org.yccheok.gui.HomeMenuFragment$Infos@4195aed0
  </code></pre>
  
  <p>I was wondering</p>
  
  <ol>
  <li>Why the proposed solution work?</li>
  <li>Is this a bug? Should we file a bug to Google regarding this behavior? Maybe there is a ticket being filed to Google, but I cannot find it.</li>
  </ol>