13

TabActivity5x をホストするがありますFragmentActivityonClick()これらのいくつかには、またはonItemClick()で新しいフラグメントを作成してプッシュするボタンまたはリストが含まれています。

ほとんどの場合、これは問題なく機能しますが、反応が鈍かったり、テスターがばかげたことをしたりした場合 (ボタンまたはリスト項目を押したままにし、別の指を使用してタブを切り替え、ボタン/リストを放します) -- 100% 再現可能)、アクティビティを一時停止して保存した後、クリック イベントが発生します。ログのスニペットを参照してください:

10-30 17:05:16.258  3415  3415 D BKC DEBUG: More.onSaveInstanceState()
10-30 17:05:16.258  3415  3415 D BKC DEBUG: MoreFragment.onPause()
10-30 17:05:17.309  3415  3415 D BKC DEBUG: MoreFragment.onItemClick()

この記事とフラグメント状態の損失に関するさまざまな StackOverflow の質問を読んだ後、これを修正する方法に対する適切な回答が見つかりません。

  • (無条件に)使用commitAllowingStateLoss()することは、実際のバグを隠す可能性のある回避策です。
  • OnClickListeners とOnItemClickListeners の登録を解除onSaveInstanceStateすることでこれが 100% 防止されるかどうかはわかりません。すべてのフラグメントのすべてのボタンに対してそれを行うのは一種の PITA です。
  • 誰かが関連するフラグメントの をチェックすることを提案しましたisAdded()が、それが機能しないことを確認できます。
  • フラグを設定しonSaveInstanceState()onRestoreInstanceState()onClick() で確認することもできますが、これもまた、面倒なことです。編集:ああ、フラグメントには がありませんがonRestoreInstanceState()、フラグをいじることはできonResume()ます。

私が見逃しているこれに対する正しい修正はありますか、それとも選択したクラッジを使用する必要がありますか?

4

4 に答える 4

4

もう少し考えてみると、それcommitAllowingStateLoss()がこの場合の正しい答えだと思います。onClick()oronItemClick()ハンドラーにいることはわかっているので、状態が失われる可能性がある場合は、 onSaveInstanceState().

私のカジュアルなテストでは、実際には何も破棄されていないため、関連するタブに戻ると新しいフラグメントが実際にポップアップします。これはユーザーにとっては少し驚くべきことですが、このエッジ ケースではおそらく許容範囲内です。

于 2013-10-31T20:07:07.927 に答える
2

I can confirm that this is a problem in the support library and not your code. The best workaround is (probably) to use the answer given by @Doge which is to track the paused state yourself.

The reason it's a problem with the support library is that onClicks happen after a click's release. If you're using multiple fingers, you can release another click event somewhere else (such as another button) which changes the fragment. The support library gets its click event after the fragment changes, and does not check to confirm it is still in the foreground. That means you have to check it yourself.

Which means that any call to setCurrentTab() or setCurrentTabByTag() must include a check for the paused state if they want to avoid this crash. Please correct me if I'm wrong.

于 2015-07-29T00:44:54.843 に答える
2

ここでのより洗練された解決策は、単にクリック イベントを無視することだと思います。アクティビティが一時停止されたときに追跡するために、BaseActivity に非常に単純なブール値フラグを設定します。

class BaseActivity extends BaseFragmentActivity {
    private boolean isPaused;

    @Override
    protected void onPause() {
        isPaused = true;
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        isPaused = false;
    }

    public boolean isPaused() {
        return isPaused;
    }
}

クリック イベントを受け取るたびに、アクティビティが一時停止されているかどうかを確認します。そうである場合は、イベントに対処する意味がないため、イベントを無視しても安全です。

@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
    if (isPaused()) {
        //But... we're paused. Ignore.
        return;
    }

    //Act upon legitimate click events here
}
于 2014-03-11T21:16:10.950 に答える
1

アクティビティが一時停止され、選択されたものに対して実行する適切なアクションがないため、実行する最善のアクションは、おそらく IllegalStateException をキャッチして食べることです。UI に実行中の処理を実行させ、FragmentTransaction を床に落とします。

于 2013-10-31T01:11:02.733 に答える