2012-08-17 51 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。