屏幕方向改变时未调用加载程序

8
当我使用AsyncTaskLoader并且屏幕方向改变时,遇到了一些麻烦。让我简要介绍一下我的应用程序结构:我有一个非常简单的应用程序,它从url获取结果并显示它。该应用程序由一个FragmentActivity和三个Fragments组成。我的三个片段如下:
  • 第一个片段是edittext和提交输入的按钮。
  • 第二个片段显示加载旋转器。
  • 第三个片段替换加载片段,以显示数据结果。
AsyncTaskLoader用于从内容提供程序(如果已缓存)或网络中加载数据。
一切都很顺利,直到屏幕方向发生改变!我查看了LoaderManager.enableDebugLogging(true)的输出,似乎问题的根源在于onLoadFinished回调没有在我的活动中被调用。
以下是启动loader的代码片段:
/* This function is defined in the "first" fragment in an interface and
 * implemented in the activity */ 
@Override
public void onFormSubmission(String word) {                     

    showLoadingFragment();

    if ( mWord == null || mWord.equals(word) ) {
        getSupportLoaderManager().initLoader(0, word, this);
    } else {
        getSupportLoaderManager().restartLoader(0, word, this);
    }

    // Store the word
    mWord = word;
}

展示结果的代码:
@Override
public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
    // Validation and other stuff

      ResultFragment fragment = new ResultFragment();

      // Add the fragment to the 'result_fragment_container' FrameLayout
      getSupportFragmentManager()
            .beginTransaction()
            .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
            .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
            // Replace loading fragment with the result
            .replace(R.id.result_fragment_container, fragment)
            .commitAllowingStateLoss(); 
}

我尝试过但失败的方法:

  • 在片段中设置setRetaininstance(true)
  • 在清单文件中设置android:configChanges="orientation|keyboardHidden|keyboard"

我已经没有更多的想法了,所以任何帮助将不胜感激。


你应该避免在onLoadFinished()方法内提交FragmentTransaction,这会影响用户体验。请参考我的博客文章了解更多信息。 - Alex Lockwood
2个回答

1
你应该将 getSupportLoaderManager().initLoader(0, null, this); 放在 onActivityCreated 方法中。如果已经存在,initLoader 将创建或重新连接一个加载器。

1

你好,我可以提供两个可能的解决方案:

1) 根据你的问题,我不确定你执行的是什么过程,它从未调用AsyncTask中的OnLoadFinished()。我假设这是一个Async DB调用或Web服务器调用等?

无论如何,onLoadFinished()可能没有被调用,因为您的Activity在旋转时被销毁。您需要保存旋转之前更新的状态,并在调用onDestroy()之前进行保存。

您可以尝试保持一个类变量状态标志。这是在您的“更新”Async任务中设置的,用于标记您的Async任务是否仍在运行,即“正在更新”还是“未更新”。

所以:

  • 当您的更新async任务开始时,bUpdating = true 。即在onPreExecute()中。
  • 当任务完成时,bUpdating = false。即在onPostExecute()中。

然后,当调用onDestroy()(始终在屏幕旋转之前调用)时,您可以检查bUpdating。如果为TRUE,则可以保存屏幕上的所有详细信息(这些详细信息已保存在Async任务中)到SharePreferences

onResume()中检查特定的SharePreferences变量,如果存在,则再次启动Async更新。

简而言之,这将:

  • 在屏幕旋转之前将详细信息保存到SharedPreferences中- onDestroy() - 如果布尔值表示异步任务正在运行。
  • 在屏幕旋转后的onResume()中检查SharedPreferences并通过Async保存详细信息。
  • 在此之后,您应该保证会调用onLoadFinished()方法。

可能还有一种更可靠的方式来检查屏幕旋转,但我没有做过太多相关工作。

2) 当然,另一种选择是在您特定的Activity上完全禁用屏幕旋转(因为实际上,在那个屏幕上你真的需要旋转吗?)。

我有一个应用程序,可以在后台记录视频并上传10秒钟的片段。它会给我的异步任务带来很大的麻烦,所以我完全禁用了旋转,因为这是完全不必要的。以下是AndroidManifest.xml文件中锁定屏幕方向为纵向的代码:

     <activity 
        android:name="com.blah.YourActivity"
        android:label="Register"
        android:screenOrientation="portrait">
    </activity>

我希望这可以帮到你。

编辑: 另外,可能有更好的分类方法来知道屏幕是否旋转:

例如这种代码:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Log.e(TAG, "ORIENTATION_LANDSCAPE");
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Log.e(TAG, "ORIENTATION_PORTRAIT");
    }
}

示例取自此帖子

你可以将SharePreferences保存在其中。但是onResume()仍然用于从中获取您的详细信息。

此外,链接到SharePreferences,以防您以前没有使用过它

编辑2!:还有一件事。我刚刚重新阅读了您的问题,并提到了“Loader”,出于某种原因,我认为这是保存数据,而不是加载数据。当onResume()被调用时,您是否尝试过简单地重新调用AsyncTaskLoader()?如果您不保存,则可以忽略我关于保留数据到SharePreferences的所有内容,因为您可以在onResume()(旋转后运行)时再次启动加载异步任务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接