8

The Busy Coder's Guide to Android Development 4.2 (ここStackOverflowのMark Murphy別名commonswareの提供)に示されているEU4Youサンプルプロジェクトを入手しました。このサンプルプロジェクトをフォローする方が簡単かもしれませんが、質問のコードの関連部分を投稿しようと思います。ActionBarSherlockプロジェクトもインポートする必要があります。また、Javaコンパイラを1.6に設定する必要があります(@Overrideアノテーションを許可するため)。

注:min-sdkを8(2.3、Froyo)に変更し、target-sdkを16(4.1、Ice Cream Sandwich)に変更しました。

注:framelayoutidをに変更しました。framelayoutidcountriesをに変更しました。left_panedetailsright_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"
/>

サンプルアプリケーションの元のバージョンには、2つのアクティビティがあります(正確にはSherlockFragmentActivities)。

  1. EU4You-適切なレイアウト(デフォルトまたは横向き-大)をロードします。デフォルトの場合、SherlockListFragmentに国のリストをロードします。横長の場合は、リストと詳細フラグメントをロードして、選択した国を表示します。
  2. DetailsActivity-横向きの大きなレイアウトを使用していない場合、DetailsFragmentを介して選択した国をロードします。

リストフラグメント内の国をクリックすると、EU4You(メインのホスティングアクティビティ)がDetailsFragmentの存在と可視性をチェックします。存在する場合は、そのフラグメント内に国のWebサイトをロードします。そうでない場合は、DetailsActivityを起動し、DetailsFragmentの追加を処理します(指定した国のWebサイトをロードします)。

これは、タブレットや携帯電話で複数の画面レイアウトをサポートする一般的なアプリケーションのように、正常に機能します。

私の問題は、DetailsActivityを削除して、単一のアクティビティに固執したいということです。大きな横向きのレイアウトではない場合(つまり、タブレットまたは任意の向きの受話器で縦向きのレイアウトになっている場合)はいつでも、リストフラグメントを詳細フラグメントに交換(置換)したいと思います。したがって、私が行ったことは、EU4YouSherlockFragmentActivityで次のように変更されています。

オリジナル(さらに上のメモに記載されているフレームレイアウト名にわずかな名前の変更があります...国は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);
    }
}

これは期待どおりに機能します。リスト上のWebサイトをクリックすると(タブレットのポートレートモード、または任意の向きの受話器で)、詳細が詳細フラグメントに表示されます。これは、Webサイトリストフラグメントを置き換えます。ただし、国の詳細が表示されているときにデバイスのホームボタンをクリックすると、次のlogcatの詳細で強制終了エラーが発生します(left_paneフレームレイアウトが1つしかないデフォルトのレイアウトのみ... 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);

置換トランザクションをバックスタックに追加できる必要があるため、この行を削除できません(このサンプルアプリケーションは、より多くのものがある実際のアプリケーションの基礎ですが、問題を単純化するために使用しました)。

したがって、2つの質問:

  1. なぜこうなった?
  2. どうすれば修正できますか(おそらく別のアプローチ)?

注意すべき点の1つは、実際のアプリケーションでは、このロジックはすべてアクションバーのタブ内にある必要があることです(バージョン2.3(Froyo)に戻る必要があるため、ActionBarSherlock)。


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

サンプルプロジェクトをGitHubに投稿しました。私はEclipseとAndroidの開発に慣れていないので、必要なものがすべて含まれていない可能性があります(ワークスペースは含まれておらず、ActionBarSherlockプロジェクトは含まれていないと思います...インポートする必要があります(ここにあります) )。

4

1 に答える 1

5

/ (単なる推測)replace()を使用するのではなく、それが関連付けられていると推測する以外は、そのエラーを確認していないため、特定のクラッシュについてコメントすることはできません。attach()detach()

しかし、getSupportFragmentManager().executePendingTransactions();私にはコードの臭いがあります。私の推測では、あなたはの利益のためにこれを行っていると思いますdetails.loadUrl(url);DetailsFragment代わりに、のようなデータメンバーを追加し、がまだ存在しない場合はそこに値urlToBeAppliedを隠してください。次に、のURLを適用できます。これがあなたのクラッシュに関して役立つかどうか、私は言うことができません。loadUrl()WebViewonCreateView()

エラーメッセージを認識する人々を頼りにしているので、問題を示す完全なサンプルプロジェクトを投稿することを検討することをお勧めします。


アップデート

サンプルアプリに基づいて、問題をより適切に診断することができました。

Content view not yet created、は、まだ通過していない、または通過したフラグメント呼び出そうListFragmentとしていることを意味します。これは通常、タイミングの問題を示しています。getListView()onCreateView()onDestroyView()

この場合、結局のところ、クラッシュしていた作業はとにかく不要でした。onSaveInstanceState()チェックされたアイテムの位置を保持しようとしているので、後で(たとえば、構成の変更後に)再チェックできます。ただし、ディスプレイを表示しているときは、そもそもチェックモードにする必要はありませんnormal。チェックされたモードはactivated状態用であり、リストと詳細が並んでいる場合は関連性がありますが、そうでない場合は関連性がありません。したがって、回避策はonSaveInstanceState()、永続的な選択が必要ない場合は、ロジックを気にしないことです...これは、を呼び出すことで簡単に取得できisPersistentSelection()ますlistener

ただし、議論のために、この作業を行う必要があったとしましょう。その場合、いくつかのオプションがあります。最も簡単なのはonDestroyView()、チェックされたアイテムの位置をオーバーライドしてキャッシュし、ifreturnsでそれを使用することonSaveInstanceState()です。getListView()null

于 2012-11-19T13:55:04.767 に答える