无法暂停活动,尚未创建内容视图

时间:2012-11-16 21:00:25

标签: android android-fragments commonsware

我抓住EU4You sample project中展示的The Busy Coder's Guide to Android Development 4.2(由Mark Murphy提供,又名commonsware来自StackOverflow)。跟随此示例项目可能更容易,但我将尝试在问题中发布相关的代码部分。您还需要导入ActionBarSherlock项目。您还需要将Java编译器设置为1.6(以允许@Override注释)。

注意:我已将min-sdk更改为8(2.3,Froyo),将target-sdk更改为16(4.1,Ice Cream Sandwich)。

注意:我已将countries framelayout ID更改为left_pane,将details framelayout ID更改为right_pane

主要布局文件(layout-large-land):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <FrameLayout
    android:id="@+id/left_pane"
    android:layout_weight="30"
    android:layout_width="0px"
    android:layout_height="fill_parent"
  />
  <FrameLayout
    android:id="@+id/right_pane"
    android:layout_weight="70"
    android:layout_width="0px"
    android:layout_height="fill_parent"
  />
</LinearLayout>

主要布局文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/left_pane"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
/>

示例应用程序的原始版本有两个活动(准确地说是SherlockFragmentActivities)。

  1. EU4You - 加载适当的布局(默认或横向大)。如果是默认值,则在SherlockListFragment中加载国家/地区列表。如果为landscape-large,则会加载列表,并显示详细信息片段以显示所选国家/地区。
  2. DetailsActivity - 当使用横向大型布局时,通过DetailsFragment加载所选国家/地区。
  3. 如果单击列表片段中的国家/地区,EU4You(主要托管活动)将​​检查DetailsFragment的存在和可见性。如果存在,则会在该片段内加载国家/地区网站。如果没有,它将触发DetailsActivity,然后处理添加DetailsFragment(然后加载给定国家/地区的网站)。

    这很好用,就像在平板电脑和手机上支持多种屏幕布局的典型应用程序一样。

    我的问题是我要删除DetailsActivity并坚持单个活动。每当我不在大型横向布局中时,我想用详细信息片段替换(替换)列表片段(换句话说,我要么是在平板电脑上的纵向布局,要么是在任何方向的手机上)。所以我所做的,改变了EU4You SherlockFragmentActivity中的以下内容:

    原始(对进一步注释中提到的framelayout名称进行轻微命名修改...国家/地区为left_pane,详情为right_pane):

    @Override
    public void onCountrySelected(Country c) {
        String url=getString(c.url);
    
        if (details != null && details.isVisible()) {
            details.loadUrl(url);
        }
        else {
            Intent i=new Intent(this, DetailsActivity.class);
    
            i.putExtra(DetailsActivity.EXTRA_URL, url);
            startActivity(i);
        }
    }
    

    我修改的单一活动版本

    @Override
    public void onCountrySelected(Country c) {
        String url=getString(c.url);
    
        if (details != null && details.isVisible()) {
            details.loadUrl(url);
        } 
        else {
            details = new DetailsFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.left_pane, details);
            ft.addToBackStack(null);
            ft.commit();
            getSupportFragmentManager().executePendingTransactions();
            details.loadUrl(url);
        }
    }
    

    这可以按预期工作。我点击列表上的一个网站(在平板电脑上以纵向模式,或在任何方向的手机上),细节片段中的详细信息显示,它取代了网站列表片段。但是,如果我然后单击设备上的主页按钮,同时显示国家/地区详细信息,我会收到强制关闭错误,并显示以下logcat详细信息(仅使用默认布局,只有单个left_pane framelayout ...我不知道当存在left_pane和right_pane时,在平板电脑上以横向方向存在此问题:

    11-16 15:04:33.525: E/AndroidRuntime(688): FATAL EXCEPTION: main
    11-16 15:04:33.525: E/AndroidRuntime(688): java.lang.RuntimeException: Unable to pause activity {com.commonsware.android.eu4you/com.commonsware.android.eu4you.EU4You}: java.lang.IllegalStateException: Content view not yet created
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3348)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3305)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3288)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.access$2500(ActivityThread.java:125)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2040)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.os.Handler.dispatchMessage(Handler.java:99)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.os.Looper.loop(Looper.java:123)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.main(ActivityThread.java:4627)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at java.lang.reflect.Method.invokeNative(Native Method)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at java.lang.reflect.Method.invoke(Method.java:521)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at dalvik.system.NativeStart.main(Native Method)
    11-16 15:04:33.525: E/AndroidRuntime(688): Caused by: java.lang.IllegalStateException: Content view not yet created
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at com.commonsware.android.eu4you.CountriesFragment.onSaveInstanceState(CountriesFragment.java:64)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.FragmentManagerImpl.saveFragmentBasicState(FragmentManager.java:1574)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1644)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:499)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at com.actionbarsherlock.app.SherlockFragmentActivity.onSaveInstanceState(SherlockFragmentActivity.java:127)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.Activity.performSaveInstanceState(Activity.java:1036)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1180)
    11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3330)
    11-16 15:04:33.525: E/AndroidRuntime(688):  ... 12 more
    

    如果我从上面的代码中删除以下行,我可以阻止此错误发生:

    ft.addToBackStack(null);
    

    我确实需要能够将替换事务添加到backstack,所以我无法删除此行(此示例应用程序是我的实际应用程序的基础,有更多的东西,但我用它来简化我的问题)。

    所以有两个问题:

    1. 为什么会这样?
    2. 我该如何修复它(也许是另一种方法)?
    3. 需要注意的一点是,在我的实际应用程序中,此逻辑必须全部属于操作栏中的选项卡(ActionBarSherlock,因为我必须支持返回2.3版(Froyo))。


      更新(2012年11月22日13:27美国东部时间)

      我在GitHub上发布了一个示例项目。我是Eclipse和Android开发的新手,因此我可能没有包含我需要的所有内容(工作区未包含在内,我认为ActionBarSherlock项目不包括在内......它需要导入(可以找到{{ 3}}))。

1 个答案:

答案 0 :(得分:5)

我无法评论您的具体崩溃,因为我没有看到该错误,只是猜测它与replace()相关而非使用attach() / detach()(只是一个猜测)。

然而,getSupportFragmentManager().executePendingTransactions();给我的是代码气味。我的猜测是你为了details.loadUrl(url);的利益而这样做。相反,请在DetailsFragment中添加数据成员,例如urlToBeApplied,如果loadUrl()尚不存在,请WebView存储值。然后,它可以在onCreateView()中应用该网址。这是否有助于你的崩溃,我不能说。

您可能希望考虑发布一个演示该问题的完整示例项目,因为您指望有人识别错误消息。


<强>更新

基于示例应用程序,我能够更好地诊断问题。

Content view not yet created上的{p> ListFragment表示我们正在尝试拨打getListView()以查找尚未通过onCreateView()的片段< / em>经历了onDestroyView()。这通常表明存在时间问题。

在这种情况下,事实证明,无论如何,崩溃的工作是多余的。 onSaveInstanceState()正试图保留已检查的项目位置,因此我们可以稍后重新检查它(例如,在配置更改后)。但是,当我们在normal显示时,我们甚至不需要首先处于检查模式。已检查模式适用于activated状态,当列表和详细信息并排时,这是相关的,但如果不是,则无关紧要。因此,如果我们不需要持久选择,那么解决方法就是不要理会onSaveInstanceState()逻辑......我们可以通过调用isPersistentSelection()上的listener来轻松获取。

但是,为了争论,让我们假装我们确实需要做这项工作。在这种情况下,我们有几个选择。最简单的可能是覆盖onDestroyView()并缓存选中的项目位置,如果onSaveInstanceState()返回getListView(),则使用null中的位置。