2012-04-16 77 views
9

我想使用演示是爲了說明這一點:裝載機無法重新啓動後的方向改變

enter code here 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    Button button = (Button) findViewById(R.id.button1); 
    button.setOnClickListener(buttonClickListener); 
} 

private OnClickListener buttonClickListener = new OnClickListener() { 

    @Override 
    public void onClick(View v) { 
     // TODO Auto-generated method stub 
     startMyLoader(); 
    } 

}; 

private void startMyLoader() { 
    getLoaderManager().destroyLoader(0); 
    getLoaderManager().restartLoader(0, null, myLoaderListener); 
} 

/** 
* The listener for the group metadata loader. 
*/ 
private final LoaderManager.LoaderCallbacks<Cursor> myLoaderListener 
    = new LoaderCallbacks<Cursor>() { 

    @Override 
    public CursorLoader onCreateLoader(int id, Bundle args) { 
     return new CursorLoader(LoaderDemoActivity.this, 
     ContactsContract.Contacts.CONTENT_URI, 
     null, null, null, null); 
    } 

    @Override 
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 
     cursor.moveToPosition(-1); 
     if (cursor.moveToNext()) { 
      Context context = getApplicationContext(); 
      CharSequence text = "Load finished!"; 
      int duration = Toast.LENGTH_SHORT; 

      Toast toast = Toast.makeText(context, text, duration); 
      toast.show(); 
     } 
    } 

    @Override 
    public void onLoaderReset(Loader<Cursor> loader) { 
    } 
}; 
enter code here 

方向改變後,我點擊該按鈕, 的onCreateLoader可以調用, 但onLoadFinished會不叫。

這似乎很奇怪。

感謝您的幫助。

回答

0

從Android的開發網站

「他們自動重新連接到時被 配置更改後重新最後加載器的指針,因此,他們並不需要 重新查詢他們的數據。」

據我瞭解,即使我們明確啓動加載程序,加載程序不會啓動。由於我們所稱的摧毀一旦被摧毀,實際上應該調用onLoaderReset()。但是,一旦方向改變,該方法就不會被調用,但之前會被調用。

我仍然可能是錯的。這是我的假設。進一步的討論將不勝感激。

3

你不需要(既不應該)摧毀你的Loader爲了重新加載它。類意圖是可重用的。

改爲使用initLoader。例如:

getLoaderManager().initLoader(0, null, myLoaderListener); 

如果要強制重裝已經註冊裝載機:

getLoaderManager().getLoader(0).forceLoad(); 

如果你是不知道,如果Loader實例配置更改事件使用的initLoader代替getLoader檢索後存在媒體鏈接您可以撥打forceLoad()的實例Loader

getLoaderManager().initLoader(0, null, myLoaderListener).forceLoad();

如果使用支持庫,然後使用forceLoad即使第一instantation後 - 有可能是一個錯誤 - 我提醒自己有關於它的這個論壇的一些問題 - 嘗試搜索舊帖子。

+0

我不認爲這是一個正確的方法來調用forceLoad()手動如果你打算使用loaderManager來控制所有這一切。 – user1335719 2012-04-17 14:42:17

+0

@ user1335719沒有這樣的限制,它只是'必須從進程的主線程調用.'並且加載程序必須啓動(檢查'isStarted()'),這在使用initLoader進行回調後很明顯。 'startLoading()'和'stopLoading' methdos用於內部使用,而不是'forceLoad'。 – 2012-04-17 15:10:38

5

我想我找到了原因。

在Activity onCreate中,它將從NonConfigurationInstances中加載所有LoaderMangers(自己的或其子片段) 。

if (mLastNonConfigurationInstances != null) { 
     mAllLoaderManagers = mLastNonConfigurationInstances.loaders; 
    } 

而在Activity onStart中,它將嘗試啓動自己的LoaderManger。

if (!mLoadersStarted) { 
     mLoadersStarted = true; 
     if (mLoaderManager != null) { 
      mLoaderManager.doStart(); 
     } else if (!mCheckedForLoaderManager) { 
      mLoaderManager = getLoaderManager(-1, mLoadersStarted, false); 
     } 
     mCheckedForLoaderManager = true; 
    } 

但配置更改後,mLoaderManager == null,所以它不會啓動它。 這就是問題所在! 如果你嘗試啓動加載器屬於這個loaderManager,它將會失敗。

void installLoader(LoaderInfo info) { 
    mLoaders.put(info.mId, info); 
    if (mStarted) { 
     // The activity will start all existing loaders in it's onStart(), 
     // so only start them here if we're past that point of the activitiy's 
     // life cycle 
     info.start(); 
    } 
} 

注意當啓動LoaderManager時mStarted值將被設置爲'true'。

有兩種方法可以解決這個問題。

  1. 調用getLoaderManger()中的onCreate(),它會重新分配mLoaderManager 並使其準備在subseuqent在onStart()啓動。

    public LoaderManager getLoaderManager(){ if(mLoaderManager!= null){ return mLoaderManager; } mCheckedForLoaderManager = true; mLoaderManager = getLoaderManager(-1,mLoadersStarted,true); 返回mLoaderManager; }

  2. 裝載器位於碎片中。因爲在Fragments的onStart(), 它將啓動它自己的LoaderManager。

    if(!mLoadersStarted){0} {0} {0} mLoadersStarted = true;如果(!mCheckedForLoaderManager){ mCheckedForLoaderManager = true; mLoaderManager = mActivity.getLoaderManager(mIndex,mLoadersStarted,false); } if(mLoaderManager!= null)mLoaderManager.doStart(); }}

+0

「但配置發生變化後,mloaderManager == null,所以它不會啓動它」 - 如果它是這樣的,那麼在調用'getLoaderManager()時會得到NullPOinterException。destroyLoader(0);' - 您可能錯過了這一點;) ,使用forceLoad並且不要破壞 - 每次都重新創建loader,因爲它違背了它的設計。 – 2012-04-17 11:14:56

+0

mLoaderManager將被賦予「getLoaderManager(-1,mLoadersStarted,false」,如果它爲null,所以它不會拋出NullPointerException異常,而且我必須重新創建加載程序,因爲它的創建中應該改變URI之類的東西。 – user1335719 2012-04-17 14:35:43

+0

謝謝,#1救了我!!! – 2012-08-22 17:52:40

13

我面臨同樣的問題。請嘗試在onCreate中調用this.getSupportLoaderManager()。 它解決了我的問題。希望這將有助於你以及

+1

之前,我在覆蓋的Activity.onStart中添加了對getLoaderManager()的調用,解決了我的問題,非常感謝!這非常有幫助!我所需要做的就是在我的onCreate中調用這個方法,並且我的裝載者在onCreate之外開始開始使用方向更改! – 2012-08-22 17:52:16

+1

我的cursorLoader在一個片段內。我發現我必須從擁有該片段的活動的onCreate方法中調用getLoaderManager()。 – daveywc 2013-03-24 23:38:21

+1

謝謝!它拯救了我的一天!標準LoaderManager也是如此。如果你打電話: onCreate()中的getLoaderManager()只是爲了初始化它,即使它不需要它,它也會更好。 – philips77 2014-05-02 09:19:28

1

確保在使用片段,你打電話給你的裝載機之前在活動onCreate

@Override 
public void onCreate(Bundle savedInstanceState) { 

    // used to not overlap fragments 
    if (savedInstanceState != null) { 
     return null; 
    } 

    loadFragments(); 

    getSupportLoaderManager().restartLoader(LISTS_LOADER, null, this); 
} 

如果您需要檢查savedInstanceState片段反正你可以檢查任何你不檢查savedStateInfo在裝載器加載完成後應該創建的類變量,因爲活動在旋轉時被破壞,但在旋轉回來時從之前的狀態升高。