2011-08-23 84 views
19

中方位發生了變化採用Android支持-v4.jar和FragmentActivity(在這一點上沒有任何碎片)如果AsyncTaskLoader運行

我有我開始加載,然後改變方向而一個AsyncTaskLoader LoaderCallbacks.onLoadFinished不叫後臺線程仍在運行。在我的日誌中,我看到響應來自後臺請求。響應完成,我期望onLoadFinished()被調用,但它永遠不會。

作爲故障排除的手段,如果我設置android:configChanges =「orientation」onLoadFinished()按預期調用。

我的活動實現了加載器回調。在LoaderManager.initLoader()的源代碼中,我發現如果加載器已經存在,則新的回調被設置爲LoaderInfo內部對象類,但是我沒有看到Loader.registerListener()再次被調用。當調用LoaderManagerImpl.createAndInstallLoader()時,似乎只調用registerListener。

我懷疑由於活動在方向更改中被銷燬並重新創建,並且因爲它是回調的偵聽器,所以新活動未被註冊以通知。

任何人都可以確認我的理解和解決方案,以便onLoadFinished後方向更改後調用?

+1

作爲另一個故障排除步驟,我添加了一個無UI的工作者Fragment和setRetainInstance爲true。碎片實現LoaderCallbacks。片段在方向更改之間保留,但onLoadFinished()方向更改後永遠不會調用片段。 – Daddyboy

+7

你在哪裏調用'initLoader()'?確保它在'onCreate()'中。順便說一句,你可以使用'LoaderManager.enableDebugLogging(true)'來獲得關於加載器生命週期的一些調試信息(在logcat中)。 –

回答

34

尼古拉發現了這個問題 - 謝謝。

我在調用initLoader fron onResume()。 Android的文檔指出:

「你通常初始化活動的onCreate()方法 或片段的onActivityCreated()方法中內的裝載機。」

與我在處理配置更改生命週期時相比,閱讀「典型」要強調一點。

我將我的initLoader調用移動到onCreate()並解決了我的問題。

我想原因是,在FragmentActivity.onCreate()LoaderManagers的集合從LastNonConfigurationInstance和FragmentActivity.onStart拉()有一些啓動關於裝載機和LoaderManagers工作。在調用onResume()時,事情已經在進行中。當Loader第一次需要實例化時,從外部onCreate()調用initLoader仍然有效。

+2

感謝您在這裏總結這一點,我用你的答案來實現碎片。它幫助了很多!另外,感謝尼古拉的信息。令人驚訝的有用的傢伙! –

+1

我有同樣的問題。但將initLoader移動到onActivityCreated()對我來說並不適用。但將它移到onCreate()上!不知道這是爲什麼...感謝一個很好的答案,幫助了很多! – Gober

+0

我也遇到了同樣的問題。這個場景解決了。但是,如果用戶鎖定手機並開始活動,則加載程序正在進行中,則不會調用onLoadFinished。 – Meher

2

這實際上不是initLoader()onCreate()這是修復它的呼籲。這是對getLoaderManager()的呼叫。總之,發生什麼事是當一個活動重新開始時,它已經知道了加載器。它試圖在你的活動命中onStart()重新啓動它們,但隨後在FragmentHostCallback.doLoaderStart() *點擊此代碼:

void doLoaderStart() { 
    if (mLoadersStarted) { 
     return; 
    } 
    mLoadersStarted = true; 

    if (mLoaderManager != null) { 
     mLoaderManager.doStart(); 
    } else if (!mCheckedForLoaderManager) { 
     mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false); 
     // WTF: Why aren't we calling doStart() here?! 
    } 
    mCheckedForLoaderManager = true; 
} 

由於getLoaderManager()尚未被調用,mLoaderManager爲空。因此,它跳過了第一個條件並致電mLoaderManager.doStart()

您可以通過撥打電話getLoaderManager()onCreate()進行測試。你不需要在那裏調用init/restart loader。

這對我來說確實是一個錯誤。

*這是代碼路徑,即使你不使用片段,所以不要因此而感到困惑。