8

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

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

注意:我已将countriesframelayout id更改为left_pane并将framelayout id 更改detailsright_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 中加载国家列表。如果横向大,加载列表和详细信息片段以显示所选国家。
  2. DetailsActivity - 在使用横向大布局时通过 DetailsFragment 加载所选国家。

如果您单击列表片段中的国家/地区,EU4You(主要托管活动)会检查 DetailsFragment 的存在和可见性。如果存在,它会在该片段中加载国家网站。如果没有,它会触发 DetailsActivity,然后处理添加 DetailsFragment(然后加载给定国家/地区的网站)。

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

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

原始(对注释中提到的框架布局名称进行了轻微的命名修改......国家是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 框架布局......我没有当存在 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);

我确实需要能够将替换事务添加到后台堆栈,所以我不能删除这一行(这个示例应用程序是我真正的应用程序的基础,它有更多的东西,但我用它来简化我的问题)。

所以两个问题:

  1. 为什么会这样?
  2. 我该如何解决它(也许是另一种方法)?

需要注意的一点是,在我的实际应用程序中,此逻辑必须全部位于操作栏中的选项卡内(ActionBarSherlock,因为我必须支持回到版本 2.3 (Froyo))。


更新(2012 年 11 月 22 日 13:27 EST)

我在GitHub 上发布了一个示例项目。我是 Eclipse 和 Android 开发的新手,所以我可能没有包含我需要的所有东西(工作空间不包括在内,我认为 ActionBarSherlock 项目不包括在内......它需要导入(可以在这里找到) )。

4

1 回答 1

5

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

但是,getSupportFragmentManager().executePendingTransactions();对我来说是一种代码味道。我的猜测是,您这样做是为了details.loadUrl(url);. 相反,请在 中添加一个数据成员DetailsFragment,例如urlToBeAppliedloadUrl()如果该值WebView尚不存在,则将值存储在那里。然后它可以将 URL 应用到onCreateView(). 我不能说这是否会对您的崩溃有所帮助。

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


更新

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

Content view not yet created, on a ListFragment, 将意味着我们正在尝试调用getListView()尚未通过onCreateView()已经通过的片段onDestroyView()。这通常表明存在时间问题。

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

不过,为了争论,让我们假设我们确实需要做这项工作。在这种情况下,我们有几个选择。最简单的可能是覆盖onDestroyView()和缓存选中的项目位置,在onSaveInstanceState()if getListView()returns中使用它null

于 2012-11-19T13:55:04.767 回答