[解決済み] アクティビティ/フラグメントが一時停止しているときのハンドラメッセージの扱い方
質問
私の 他の投稿
基本的に、私はメッセージ
Handler
の中に
Fragment
で、これはダイアログを閉じたり表示したりすることになる、たくさんのメッセージを受け取ります。
アプリがバックグラウンドになったとき、私は
onPause
が表示されますが、期待どおりにメッセージは表示されます。しかし、フラグメントを使用しているため、ダイアログを閉じたり表示したりすることはできません。
IllegalStateException
.
状態異常を許可しているのを解除したり、キャンセルしたりするのは
ということを考えると、私は
Handler
があることを考えると、一時停止中にメッセージをどのように扱うべきかについて、推奨されるアプローチがあるかどうか疑問に思います。
どのように一時停止状態のメッセージを処理すべきかについて、推奨されるアプローチがあるかどうか。
私が考えている 1 つの可能な解決策は、一時停止中に送られてくるメッセージを記録し、それを
onResume
. これはやや不満足で、これをよりエレガントに処理するフレームワークの何かがあるに違いないと思っています。
どのように解決するのですか?
Android オペレーティング システムには、この問題に十分に対応するメカニズムがないように見えますが、このパターンは比較的簡単に実装できる回避策を提供するものだと考えています。
次のクラスは
android.os.Handler
のラッパーで、アクティビティが一時停止したときにメッセージをバッファリングし、再開時にそれらを再生します。
フラグメントの状態を非同期に変更するコード (例: commit, dismiss) が、ハンドラ内のメッセージからのみ呼び出されることを確認します。
ハンドラを
PauseHandler
クラスから派生させます。
あなたのアクティビティが
onPause()
を呼び出します。
PauseHandler.pause()
そして
onResume()
呼ぶ
PauseHandler.resume()
.
ハンドラの実装を置き換える
handleMessage()
を
processMessage()
.
の簡単な実装を提供します。
storeMessage()
を常に返す単純な実装を提供する。
true
.
/**
* Message Handler class that supports buffering up of messages when the
* activity is paused i.e. in the background.
*/
public abstract class PauseHandler extends Handler {
/**
* Message Queue Buffer
*/
final Vector<Message> messageQueueBuffer = new Vector<Message>();
/**
* Flag indicating the pause state
*/
private boolean paused;
/**
* Resume the handler
*/
final public void resume() {
paused = false;
while (messageQueueBuffer.size() > 0) {
final Message msg = messageQueueBuffer.elementAt(0);
messageQueueBuffer.removeElementAt(0);
sendMessage(msg);
}
}
/**
* Pause the handler
*/
final public void pause() {
paused = true;
}
/**
* Notification that the message is about to be stored as the activity is
* paused. If not handled the message will be saved and replayed when the
* activity resumes.
*
* @param message
* the message which optional can be handled
* @return true if the message is to be stored
*/
protected abstract boolean storeMessage(Message message);
/**
* Notification message to be processed. This will either be directly from
* handleMessage or played back from a saved message when the activity was
* paused.
*
* @param message
* the message to be handled
*/
protected abstract void processMessage(Message message);
/** {@inheritDoc} */
@Override
final public void handleMessage(Message msg) {
if (paused) {
if (storeMessage(msg)) {
Message msgCopy = new Message();
msgCopy.copyFrom(msg);
messageQueueBuffer.add(msgCopy);
}
} else {
processMessage(msg);
}
}
}
以下は、簡単な例で
PausedHandler
クラスが使用できる簡単な例です。
ボタンがクリックされると、遅延メッセージがハンドラに送信されます。
ハンドラがメッセージを受信すると (UI スレッドで)
DialogFragment
.
もし
PausedHandler
クラスが使用されていない場合、ダイアログを起動するためにテストボタンを押した後にホームボタンを押すと、IllegalStateExceptionが表示されるでしょう。
public class FragmentTestActivity extends Activity {
/**
* Used for "what" parameter to handler messages
*/
final static int MSG_WHAT = ('F' << 16) + ('T' << 8) + 'A';
final static int MSG_SHOW_DIALOG = 1;
int value = 1;
final static class State extends Fragment {
static final String TAG = "State";
/**
* Handler for this activity
*/
public ConcreteTestHandler handler = new ConcreteTestHandler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public void onResume() {
super.onResume();
handler.setActivity(getActivity());
handler.resume();
}
@Override
public void onPause() {
super.onPause();
handler.pause();
}
public void onDestroy() {
super.onDestroy();
handler.setActivity(null);
}
}
/**
* 2 second delay
*/
final static int DELAY = 2000;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (savedInstanceState == null) {
final Fragment state = new State();
final FragmentManager fm = getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
ft.add(state, State.TAG);
ft.commit();
}
final Button button = (Button) findViewById(R.id.popup);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final FragmentManager fm = getFragmentManager();
State fragment = (State) fm.findFragmentByTag(State.TAG);
if (fragment != null) {
// Send a message with a delay onto the message looper
fragment.handler.sendMessageDelayed(
fragment.handler.obtainMessage(MSG_WHAT, MSG_SHOW_DIALOG, value++),
DELAY);
}
}
});
}
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
}
/**
* Simple test dialog fragment
*/
public static class TestDialog extends DialogFragment {
int value;
/**
* Fragment Tag
*/
final static String TAG = "TestDialog";
public TestDialog() {
}
public TestDialog(int value) {
this.value = value;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View inflatedView = inflater.inflate(R.layout.dialog, container, false);
TextView text = (TextView) inflatedView.findViewById(R.id.count);
text.setText(getString(R.string.count, value));
return inflatedView;
}
}
/**
* Message Handler class that supports buffering up of messages when the
* activity is paused i.e. in the background.
*/
static class ConcreteTestHandler extends PauseHandler {
/**
* Activity instance
*/
protected Activity activity;
/**
* Set the activity associated with the handler
*
* @param activity
* the activity to set
*/
final void setActivity(Activity activity) {
this.activity = activity;
}
@Override
final protected boolean storeMessage(Message message) {
// All messages are stored by default
return true;
};
@Override
final protected void processMessage(Message msg) {
final Activity activity = this.activity;
if (activity != null) {
switch (msg.what) {
case MSG_WHAT:
switch (msg.arg1) {
case MSG_SHOW_DIALOG:
final FragmentManager fm = activity.getFragmentManager();
final TestDialog dialog = new TestDialog(msg.arg2);
// We are on the UI thread so display the dialog
// fragment
dialog.show(fm, TestDialog.TAG);
break;
}
break;
}
}
}
}
}
を追加しました。
storeMessage()
メソッドに
PausedHandler
クラスに追加することができます。メッセージが処理された場合、falseが返され、メッセージは破棄されます。
関連
-
[解決済み】フラグメントMyFragmentがアクティビティにアタッチされない。
-
[解決済み] Androidでアクティビティ起動時にEditTextにフォーカスが当たらないようにする方法
-
[解決済み] インスタンス状態の保存を使用してアクティビティ状態を保存するにはどうすればよいですか?
-
[解決済み] ViewPagerでFragmentが表示されるタイミングを決定する方法
-
[解決済み] AndroidでFragmentにオプションメニューを追加する方法
-
[解決済み] フラグメントからアクティビティメソッドを呼び出す
-
[解決済み] Androidでアクティビティからフラグメントにデータを送信する
-
[解決済み】Androidで透明なActivityを作成する方法は?
-
[解決済み] フラグメント間の値の受け渡し方法
-
[解決済み] AsyncTaskLoaderとAsyncTaskの比較
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] ベストプラクティスです。方向転換中のAsyncTask
-
[解決済み] Androidでマイナスマージンを使用するのは悪いことですか?
-
[解決済み] 「KotlinとAndroidで「パラメータTを推測するのに十分な情報がありません。
-
[解決済み] Android ConstraintLayout - あるビューを別のビューの上に配置する
-
[解決済み] Android Navigation Architecture Component - 現在表示されているフラグメントを取得する
-
[解決済み] Android Studio - あいまいなメソッド呼び出し getClass()
-
[解決済み] これはどういうことですか?失敗 [INSTALL_FAILED_CONTAINER_ERROR]?
-
[解決済み] Androidアプリケーションのヒープサイズを大きくするには?
-
[解決済み] EditTextの右側のDrawableにonClickListenerを設定する [重複] [重複
-
[解決済み] Travis.yml ./gradlew : パーミッションが拒否されました。