2012-08-17 48 views
18

在Android文檔裝載機發現在http://developer.android.com/guide/components/loaders.html重新啓動它說裝載機的特性之一是:裝載機的方向變化

配置更改後正在重建時,它們會自動重新連接到最後加載器的光標。因此,他們不需要重新查詢他們的數據。

下面的代碼似乎並沒有反映這種行爲,一個新的Loader創建一個完成查詢ContentResolver的,那麼我旋轉屏幕,並重新創建的裝載機!

public class ReportFragment extends Fragment implements LoaderCallbacks<Cursor> { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     getLoaderManager().initLoader(1, null, this); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     View v = inflater.inflate(R.layout.fragment_report, container, false); 
     return v; 
    } 

    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { 
     Log.d("TEST", "Creating loader"); 
     return new CursorLoader(getActivity(), ResourcesContract.Reports.CONTENT_URI, null, null, null, null); 
    } 

    public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) { 
     Log.d("TEST", "Load finished"); 
    } 

    public void onLoaderReset(Loader<Cursor> arg0) { 

    } 

} 

這裏是我的logcat輸出:

08-17 16:49:54.474: D/TEST(1833): Creating loader 
08-17 16:49:55.074: D/TEST(1833): Load finished 
*Here I rotate the screen* 
08-17 16:50:38.115: D/TEST(1833): Creating loader 
08-17 16:50:38.353: D/TEST(1833): Load finished 

任何想法,我做錯了什麼?

編輯:

我要指出,我建設,以谷歌Android API的8版本,並使用V4支持庫。

2日編輯:

這很可能是由於在支持庫中的錯誤,如果你想了解更多信息,看看這個bug提交:

http://code.google.com/p/android/issues/detail?id=20791&can=5&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

+1

看到這篇文章的更多信息:http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html – 2012-08-23 16:30:55

+2

此外,你應該調用'getLoaderManager()'onActivityCreated' ...你當前的代碼如果在第一次創建'Fragment'時'Activity'仍然是'null',將拋出'IllegalStateException'。 – 2012-08-23 16:37:52

+1

@AlexLockwood,在您使用support-v4:18.0.0的例子中(做得好!)。當前版本是23.0.1,它包含這個錯誤。我測試的最新工作版本是22.0.0。 – 2015-09-24 08:58:54

回答

-2

的onCreate( )在屏幕方向更改期間被調用,因爲活動被破壞並重新創建。除非你加載了大量的數據,否則它並沒有傷害,但如果你想要的話,你可以嘗試以下(我沒有測試過,但理論上我認爲它會工作)。

在類的頂部全局聲明一個靜態布爾值。我認爲你還需要一個靜態遊標引用

private static boolean dataDownloaded = false; 
private static Cursor oldCursor; 

然後在onLoadFinished設置dataDownloaded =真

的onSaveInstanceState覆蓋保存布爾值

@Override 
protected void onSaveInstanceState(Bundle outSave) { 
    outSave.putBoolen("datadownloaded", dataDownloaded); 
    oldCursor = adapter.swapCursor(null); 
} 

和的onCreate添加以下

if (savedInstanceState != null) { 
    this.dataDownloaded = savedInstanceState.getBoolean("datadownloaded", false); 
} 

調整onCreateLoader

public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    CursorLoader cursorLoader; 
    if (dataDownloaded) { 
     cursorLoader = new CursorLoader(getActivity(), 
      null, projection, null, null, null); 
     cursorLoader.deliverResult(oldCursor); 
    } else { 
     CursorLoader cursorLoader = new CursorLoader(getActivity(), 
      URI_PATH, projection, null, null, null); 
    } 

    return cursorLoader; 
} 
+0

不會這樣查詢ContentResolver(如果dataDownloaded是true或false,是否仍然創建一個新的CursorLoader並不重要)?無論如何,我認爲這實際上是因爲支持庫的錯誤而發生的,請參閱此帖以獲取更多信息:https://groups.google.com/forum/?fromgroups#!topic/android-developers/DbKL6PVyhLI%5B1- 25%5D – 2012-08-17 18:43:42

+0

我調整了它..如果數據已經被下載,它應該是URI的「空」 – ainesophaur 2012-08-17 19:03:01

+0

現在有道理。那麼,就我所見,這是一個解決方案,所以我會將其標記爲一個。感謝您的回答。 – 2012-08-18 17:51:46

-1

你可以簡單地檢查,看看是否裝載機已經存在的onCreate。然後,您可以啓動或重新啓動。

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    if (getLoaderManager().getLoader(LOADER_ID) == null) { 
     getLoaderManager().initLoader(LOADER_ID, null, this); 
    } else { 
     getLoaderManager().restartLoader(LOADER_ID); 
    } 
} 

您通常會將ID傳遞給您的加載程序,以便您稍後可以通過加載程序管理器來引用它。

希望這會有所幫助!

+0

嗨尼爾森,這將重新啓動加載器,如果已經存在一個,哪種藐視它的目的。即使你要切換這兩個語句(init和restart),它也會導致和剛纔調用initLoader一樣的行爲! – 2012-08-17 18:58:06

+2

getLoaderManager()。restartLoader(LOADER_ID);與完整的「if(){} else {}」語句完全相同,因爲如果Loader尚不存在,那麼restartLoader完全相同。 – 2014-01-16 01:49:16

0

到目前爲止,我發現保留片段Fragment.setRetainInstance(true)可以防止在使用支持庫的情況下重新定位裝載程序。裝載機最後的結果很好地在onLoadFinished()交付。至少在活動管理單個片段時使用FragmentTransaction將片段添加到活動中。

0

雖然這是一個古老的問題,我想把我的看法放在這裏。

沒有必要在

的onSaveInstanceState

存儲額外的信息配置更改後重新被當框架自動重新連接到最後加載器的光標。因此,他們不需要重新查詢他們的數據。

這意味着在OnCreate函數,你需要調用loaderManager只有在savedInstanceState是空

例:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    if(savedInstanceState == null) { 
     getLoaderManager().initLoader(1, null, this); 
    } 
} 
1

儘管這是一個老問題了,我已經遇到了同樣的問題,因爲OP。使用加載器時,我需要在導航到新的「活動」時重新啓動,然後返回。但與此同時,我不希望裝載機在我旋轉手機屏幕時重新啓動。

我發現,如果您在調用超級加載程序之前重新啓動加載程序,可以在onRestart()中實現此目標。

public class MainActivity extends AppCompatActivity implements 
LoaderManager.LoaderCallbacks<Cursor> { 

    ... 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     ... 

     //Initialize the loader. 
     getSupportLoaderManager().initLoader(0, null, this); 
    } 

    @Override 
    protected void onRestart() { 
     //Restart the loader before calling the super. 
     getSupportLoaderManager().restartLoader(LOADER_ID, null, this); 

     super.onRestart(); 
    } 

    ... 

} 
+0

+1謝謝:)這幫助了我的問題:)我使用AdapterViewFlipper並按照您的建議來管理我的加載器鰭狀肢不受屏幕旋轉的影響:) – 2017-08-13 10:02:23

0

在我看來你錯誤地理解了文檔中的內容。文件說,他們不需要重新查詢他們的數據,它不這樣做。

嘗試在您的ContentProvider#query()方法中記錄/插入斷點!查詢將僅在Activity啓動時被調用,而不會在方向更改後調用。

但是這對於LoaderCallbacks#onCreateLoader()方法並不正確。它會在每個方向更改後調用,但這不意味着重新查詢,它只是調用方法,以便您可以更改CursorLoader。