【Android】復帰時のBGMのリジューム

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

【Android】復帰時のBGMのリジューム

#1

投稿記事 by みけCAT » 13年前

Eclipse Version:3.7.2
docomo SC-03D ( Galaxy SII LTE )

前のトピックでホームボタンを押したあとにゲームに戻る方法を聞いて実装しましたが、一つ問題があります。
それは、BGMが復帰直後に再生されないことです。
MediaPlayerを持ったSoundManagerオブジェクトを直接保存しようとしてもだめ、
SoundManagerオブジェクトから再生中のBGMのIDを引き出し、復帰時にそれを再生しようとしてもだめでした。
(添付のプロジェクトでは後者を実装しています)
添付のプロジェクトではBGMを1種類しか積んでいませんが、実際のゲームには2種類のBGMがあり、
一旦BGMを切り替えてから再生しなかったBGMのシーンに行くときちんと再生されます。
どのようにすれば復帰直後からBGMが再生できるでしょうか?
できれば切れたところからBGMを再生したいですが、無理なら最初からでもかまいません。
よろしくお願いします。
添付のプロジェクトではカウントが50000になった時からBGMを再生します。
添付ファイル
bgmmintest.zip
プロジェクトです。
(1.17 MiB) ダウンロード数: 150 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#2

投稿記事 by ISLe » 13年前

プロジェクトは見てませんが、MediaPlayerなら、終了時にはgetCurrentPositionで再生位置を記録、復帰時にはseekToで再生位置を指定後再生開始という手順になるかと。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#3

投稿記事 by みけCAT » 13年前

それをやってみましたが、他の場所の問題だと思います。
Toastで調べてみたところ、ゲームの起動時にSoundManagerを格納する変数がnullの状態でゲームデータ取得関数が呼ばれ、
その後ホームボタンを押した時にもゲームに戻る時にもゲームデータ取得関数は呼ばれていませんでした。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#4

投稿記事 by ISLe » 13年前

サウンドのようなネイティブなリソースにアクセスする部分ではタイミングの問題があるかもしれません。
復帰後メインループが安定してからBGMの再生を開始するようにする必要があると思います。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#5

投稿記事 by みけCAT » 13年前

ActivityのonRetainNonConfigurationInstance関数が
Activity破棄時(ホームボタンを押したとき)に呼ばれることを期待してプログラミングしているのですが、
Toastで調べると、ゲームの起動時に呼ばれ、破棄時には呼ばれていないようです。
使い方が間違っているでしょうか?
代わりに何を使えばいいでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#6

投稿記事 by ISLe » 13年前

onRetainNonConfigurationInstanceで返すオブジェクトを受け取るのは、異なるActivityのインスタンスであることは理解されているでしょうか。
新しいインスタンスが起動され、古いインスタンスが破棄される寸前という状態です。

データの引き継ぎはonRetainNonConfigurationInstance→getLastNonConfigurationInstanceの方法でかまいませんが、実質的な退避・復帰の処理はActivityのライフサイクルに沿ってイベントメソッドに実装すべきかと思います。
同時に2つのインスタンスが存在する瞬間があるわけなので、リソースの解放や確保などの処理は適切なタイミングで行われなければいけません。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#7

投稿記事 by みけCAT » 13年前

ログなどを取って試行錯誤した結果、
アプリをホームボタンで閉じて再び開いた時にonCreateや
SurfaceViewのコンストラクタが呼ばれないことがわかりました。
そこで、もしかしたらもとのSurfaceViewが残っているかもしれないと思い、
ループ中に毎フレームBGMの状態を取得してみたところ、無事BGMをリジュームすることができました。
添付ファイル
bgmmintest_new.zip
プロジェクトです。
(1.17 MiB) ダウンロード数: 135 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#8

投稿記事 by ISLe » 13年前

みけCAT さんが書きました:アプリをホームボタンで閉じて再び開いた時にonCreateや
SurfaceViewのコンストラクタが呼ばれないことがわかりました。
Androidは、メモリに余裕があれば、インスタンスを破棄しないで再利用します。
メモリに余裕が無くなると破棄され、その後起動されるときにはonCreateが呼ばれます。
電池の消耗を防ぐアプリなどが入っていると速攻で破棄されることもあります。
〇〇の操作で終了したから破棄される/されないという決め付けをしてはいけません。

ライフサイクルにそって、onPauseでBGMの再生位置を記録して再生停止、onResumeで再生開始するのが王道かと思います。
onCreateでデータの引き継ぎを済ませていればonResumeの処理は初回時でも復帰時でも同じにできます。

ライフサイクルとイベントメソッドの関係については、Activities | Android Developersの中程にある図が分かりやすいと思います。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#9

投稿記事 by みけCAT » 13年前

onPauseでデータをバックアップ用のオブジェクトに記録し、
スレッドの開始時にBGMの再生を始める(変更なし)ようにしてみましたが、
これでマズいことが起きるのは例えばどのようなときでしょうか?
添付ファイル
bgmmintest_new2.zip
プロジェクトです。
(1.17 MiB) ダウンロード数: 155 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#10

投稿記事 by ISLe » 13年前

ViewのsurfaceCreatedでスレッドを作成し直しているので問題ないのではないでしょうか。

他のActivityがViewの一部を上書きするような表示の仕方をすれば、Viewが破棄されずにバックグラウンドに回ることがある気もします。
いま現在そういうことがあるのかどうか分かりませんが、そういう状況ではアプリの挙動として問題になるかもしれません。

あとシステムがスレッドを待機状態にするタイミングによっては終了判定に失敗してスレッドが増えていく可能性があると思います。


個人的にはViewにアプリのメインスレッドを入れるのは気持ち悪いですね。
複数のViewを配置したら、それぞれのViewで別のゲームが動くか、同じゲームの画面が別々に表示されるかという設計の違いなのですが。
前者もアリですが、世のサンプルプログラムは知る限り、ActivityとViewで機能がきちんと分離できてないどっちつかずです。


TheViewクラスの引数が1つのコンストラクタの中身を
this(context, null);
にすると引数が2つのコンストラクタにまとめられるので同じコードをメンテする手間を省けます。
どっちのコンストラクタを呼び出したかのログ出力は混じってしまいますけど。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#11

投稿記事 by みけCAT » 13年前

ISLe さんが書きました:ViewのsurfaceCreatedでスレッドを作成し直しているので問題ないのではないでしょうか。

他のActivityがViewの一部を上書きするような表示の仕方をすれば、Viewが破棄されずにバックグラウンドに回ることがある気もします。
いま現在そういうことがあるのかどうか分かりませんが、そういう状況ではアプリの挙動として問題になるかもしれません。
(´ε`;)ウーン…
ISLe さんが書きました:あとシステムがスレッドを待機状態にするタイミングによっては終了判定に失敗してスレッドが増えていく可能性があると思います。
run関数の最初で

コード:

Thread myThread=Thread.currentThread();
とし、

コード:

_thread!=null
の代わりに

コード:

_thread==myThread
としてみました。
これでどうでしょうか?
ISLe さんが書きました:個人的にはViewにアプリのメインスレッドを入れるのは気持ち悪いですね。
複数のViewを配置したら、それぞれのViewで別のゲームが動くか、同じゲームの画面が別々に表示されるかという設計の違いなのですが。
前者もアリですが、世のサンプルプログラムは知る限り、ActivityとViewで機能がきちんと分離できてないどっちつかずです。
なるほど、このことですね。
次回から意識してみます。
Activityでスレッドを走らせ、保存しておいたView(SurfaceView)のonDraw関数か自作の描画関数を呼ぶ、ということですか?

ISLe さんが書きました:TheViewクラスの引数が1つのコンストラクタの中身を
this(context, null);
にすると引数が2つのコンストラクタにまとめられるので同じコードをメンテする手間を省けます。
どっちのコンストラクタを呼び出したかのログ出力は混じってしまいますけど。
なるほど、thisでしたか。
クラス名を書いてもう一つのコンストラクタを呼ぼうとして失敗したので、とりあえずこのような実装にしてしまいました。
オフトピック
プロジェクトの仕様変更をしました。
時間計測をスタートからの時間から差分に変更し、表示していない間はカウントダウンしないようにしました。
添付ファイル
bgmmintest_new3.zip
プロジェクトです。
(1.18 MiB) ダウンロード数: 145 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: 【Android】復帰時のBGMのリジューム

#12

投稿記事 by ISLe » 13年前

みけCAT さんが書きました:これでどうでしょうか?
それなら大丈夫ですね。
みけCAT さんが書きました:Activityでスレッドを走らせ、保存しておいたView(SurfaceView)のonDraw関数か自作の描画関数を呼ぶ、ということですか?
Androidに限らないのですが、考え方としてはViewはあくまで描画のためで、Viewが無くても内部的にはゲームがきちんと動くように作るのが理想ですね。
あとViewはユーザーからの入力を受け取る窓口でもあるのでシンプルにインターフェースとしての機能だけを持たせるべきかと思います。
あくまで個人的な考えですが。

例えばGLSurfaceViewを使う場合だと、テクスチャはGLSurfaceView.Rendererのコンテキスト経由で作ることになるので、必然的にGLSurfaceView.Rendererがイメージ管理クラス的な位置付けになります。
View(GLSurfaceView)はユーザーからの入力を受け付けるだけとなり役割分担がはっきりします。

SurfaceViewと同じに見えるようわざと混ぜこぜにしているサンプルプログラムをしばしば見掛けますけどね。

閉鎖

“C言語何でも質問掲示板” へ戻る