3

私の設定は次のとおりです。

2つのフラグメントをロードするアクティビティから呼び出されたFragmentPagerAdapterがあります。これはonCreate内で設定されます。

onResumeでは、データベースからデータをロードするASyncTaskを呼び出してから、ロードデータリスナーを介してアクティビティonLoadCompleteでコールバックを呼び出します。

    @Override
public void onLoadComplete(JSONArray data) {
    // TODO Auto-generated method stub


    LocalFragment fragmentB = (LocalFragment)getSupportFragmentManager().findFragmentByTag(ListTag);
    fragmentB.setList(data);

    LMapFragment fragmentA = (LMapFragment)getSupportFragmentManager().findFragmentByTag(MapTag);

    GoogleMap our_map = fragmentA.getMap();
    fragmentA.plotP(myLocation,data);

}

フラグメントはPagerによって初期化され、各フラグメントコード内で、たとえばLocalFragmentでそれぞれのタグを設定します。

    @Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);

    String myTag = getTag();



        ((PagerTest) activity).setListTag(myTag);
        Log.d("what",myTag);


}

これにより、フラグメントにアクセスしたり、リストにデータを入力したり、マップにデータを入力したりする関数を呼び出すことができます。できます。

私が今やろうとしているのは、画面の向きの変更を説明することです。ASyncTaskの実行中に向きが変更されると、アプリがクラッシュします。

ここで提案されているように:隠しフラグメントASyncTaskの状態を保存する隠しフラグメントを実装しようとしています。だから私がやったことはそれを設定することです私の活動のonResumeで私は関数を呼び出します

    static LoadDataFromURL the_data = null;
static JSONArray pub_data = null;
private static final String TAG = "RetainFragment";

public RetainFragment() {}

public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {

    RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
    if (fragment == null) {
        fragment = new RetainFragment();
        fm.beginTransaction().add(fragment, TAG).commit(); // add this
    }
    return fragment;
}

これは基本的に私のデータを保存します。

基本的に、これが意味するのは、画面を回転させても、ASyncTaskを再度呼び出さないことです。画面が回転するだけです。完全に機能します。

ただし、メインメニューに戻ってアクティビティをもう一度クリックすると、画面は空白になります(ただしクラッシュしません)。私の理解では、データはフラグメント内のオブジェクトとして保持されますが、アクティビティを新たにリロードするときに、データを再度設定する必要があります。リスト/マップにデータを入力するには、IEonLoadCompleteを呼び出す必要があります。

したがって、最初にASyncTaskが完了した後、返されたデータを非表示のフラグメントonRetainInstanceに保存すると、onLoadCompleteを呼び出して渡すことができると結論付けました。

問題は、この状況では、タグがnullであるため、フラグメントがまだ呼び出されていないように見え、onLoadComplete内でコールバックを呼び出すとアプリがクラッシュすることです。

私は何年もの間これに頭をぶつけてきました。

私のASyncTaskは別のクラスにあります:LoadDataFromURL達成したいのは次のとおりです-画面上の回転でASyncTaskが回転/新しいアクティビティにアタッチされたままになり、完了した場合は再度実行しないようにするfragmentviewpager ..

誰かアドバイスしてもらえますか?

どうもありがとう

編集

シークレットフラグメントの変数をパブリック変数に変更したので、すべてが一緒になっているように見えます。しかし、どのように/いつ呼び出されるかが100%わからないため、なぜそれが機能するのか完全には理解できません。

つまり、findOrCreateRetainFragmentを呼び出すと、新しい「シークレット」フラグメントが作成されるか、現在のインスタンスが返されます。

現在のインスタンスを返している場合は、非同期タスクを再度呼び出さないでください。そうでない場合は、非同期タスクを呼び出してデータをロードします。

この設定では、アクティビティを読み込んで画面を回転させると、期待どおりに回転します。

ここで、メインメニューに戻ってアクティビティをもう一度クリックすると、非同期タスクが呼び出されます。

私の理解では、ローテーション時に非同期タスクが再度呼び出されることはなく、viewpagerはどういうわけかフラグメントを保存しています。

一方、戻ると、秘密のフラグメントと同様にアクティビティが破棄されます。そのため、もう一度クリックすると、データが読み込まれます。これは本質的に私が欲しいものです。

私はこれを正しく理解しましたか?

ありがとう

4

1 に答える 1

5

あなたが経験しているいくつかの問題がここにあります(私は思います)。

まず第一に、コールバックがクラッシュする理由はActivity、画面の向きやActivityプッシュの後に「存在しない」古いコールバックに接続されているためです。onAttach()フラグメントにコールバックをアタッチするために使用する場合は、フラグメントがから削除されたときに、を使用してそのコールバックをデタッチする必要があります。次に、コールバックを呼び出すたびにnullをチェックして、デッドオブジェクトにデータを送信しないようにします。onDetach()Activity

基本的に、ここで使用しようとしているロジックは次のとおりです。

  1. アクティビティを開始します。

  2. フラグメントが存在するかどうかを確認します。もしそうなら、それをつかみます。それ以外の場合は、作成します。

  3. データが存在する場合は取得します。そうでない場合は、コールバックを待ちます。

コールバックの性質上(実装によって異なります)、イベントが発生するまでデータを受信しません。ただし、アクティビティがなくなり、イベントがすでに発生している場合、コールバックは実行されません。したがって、データを手動で取得する必要があります。を使用する場合setRetainInstance()は、このエンティティがアクティビティから切り離されていると考えると便利です。現在をポップしActivityたり、新しいをプッシュしたりしない限り、存在しますActivity。ただし、Activity画面の向きを変更すると、現在の電流は破棄されますが、破棄されFragmentません。そのため、Fragmentはの存在に依存するべきではありませんActivity

調査したい問題に対するはるかに洗練された解決策は、AndroidLoaderAPIを実装することです。ローダーは、システムによって処理される便利なツールであり、ほぼ同じように機能しますが、非同期でデータを取得することでより調和します。それらは同じように効果的に機能します。ローダーとシステムを起動するだけで、ローダーが存在しない場合は作成するか、既存のローダーを再利用できます。構成が変更されると、システムに残りLoaderManagerます。

編集:

あなたの編集に答えるために、私は何が起こっているのかを説明すると思います。複雑なので、何か説明が必要な場合は教えてください。

フラグメントは、技術的に言えば、現在実行中の一部ではありませんActivity。Fragmentのインスタンスを作成するときは、FragmentManagerを呼び出す必要がありbeginTransation()ますcommit()。FragmentManagerは、アプリケーションの領域内に存在するシングルトンです。FragmentManagerは、のインスタンスを保持しFragmentます。次に、FragmentManagerはフラグメントをアクティビティに添付します(を参照onAttach())。その場合、フラグメントはFragmentManager内に存在します。そのため、アプリケーション内でフラグメントへの参照を実際に保持する必要はありません。呼び出すだけfindFragmentByTag/Id()で取得できます。

通常の状況では、アクティビティが破棄されると、FragmentManagerはフラグメントのインスタンスをデタッチし(を参照onDetach())、そのまま放します。Javaガベージコレクションは、フラグメントへの参照が存在しないことを検出し、それをクリーンアップします。

を呼び出すときsetRetainInstace()は、FragmentManagerにそれを保持するように指示しています。したがって、構成の変更でアクティビティが破棄されている場合、FragmentManagerはフラグメントの参照を保持します。findFragmentByTag/Id()したがって、アクティビティが再構築されたときに、最後のインスタンスを取得するために呼び出すことができます。最後のアクティビティのコンテキストが保持されていない限り、問題は発生しないはずです。

従来は、これを使用して、(あなたがそうであるように)長年のデータへの参照を保持したり、電話のフリップでデータが削除されないように接続ソケットを開いたままにしたりしていました。

ViewPagerはこれとは何の関係もありません。フラグメントを取得する方法は、接続されているアダプタを実装する方法に完全に依存します。通常、保持されたフラグメントにはビュー自体がありません。これは、ビューが作成されたアクティビティのコンテキストデータを保持しているためです。基本的には、ビューが作成されたときにビューがプルするデータを保持するデータバケットにします。膨らんでいる。

于 2012-12-21T14:18:42.260 に答える