[解決済み] Android "ビュー階層を作成した元のスレッドだけがそのビューに触れることができます。"
2022-01-30 16:28:30
質問
Androidで簡単な音楽プレーヤーを作りました。各曲のビューにはSeekBarが含まれており、以下のように実装されています。
public class Song extends Activity implements OnClickListener,Runnable {
private SeekBar progress;
private MediaPlayer mp;
// ...
private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService = ((MPService.LocalBinder)rawBinder).getService(); // service that handles the MediaPlayer
progress.setVisibility(SeekBar.VISIBLE);
progress.setProgress(0);
mp = appService.getMP();
appService.playSong(title);
progress.setMax(mp.getDuration());
new Thread(Song.this).start();
}
public void onServiceDisconnected(ComponentName classname) {
appService = null;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
// ...
progress = (SeekBar) findViewById(R.id.progress);
// ...
}
public void run() {
int pos = 0;
int total = mp.getDuration();
while (mp != null && pos<total) {
try {
Thread.sleep(1000);
pos = appService.getSongPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
progress.setProgress(pos);
}
}
これは問題なく動作します。今度は、曲の進行の秒/分をカウントするタイマーが欲しい。そこで
TextView
をレイアウトに追加し、それを
findViewById()
で
onCreate()
で、これを
run()
の後に
progress.setProgress(pos)
:
String time = String.format("%d:%d",
TimeUnit.MILLISECONDS.toMinutes(pos),
TimeUnit.MILLISECONDS.toSeconds(pos),
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(
pos))
);
currentTime.setText(time); // currentTime = (TextView) findViewById(R.id.current_time);
しかし、最後の行で例外が発生します。
android.view.ViewRoot$CalledFromWrongThreadException: ビュー階層を作成した元のスレッドだけが、そのビューに触れることができます。
しかし、私がここでやっていることは、基本的に
SeekBar
- でビューを作成します。
onCreate
でタッチし、それを
run()
- で、この苦情は出ません。
解決方法は?
バックグラウンドタスクのうち、UIを更新する部分をメインスレッドに移動させる必要があります。そのための簡単なコードがあります。
runOnUiThread(new Runnable() {
@Override
public void run() {
// Stuff that updates the UI
}
});
のドキュメント
Activity.runOnUiThread
.
これをバックグラウンドで動作しているメソッド内にネストし、ブロックの途中に更新を実装するコードをコピーペーストするだけです。できるだけ小さなコードだけを含めるようにします。そうしないと、バックグラウンド・スレッドの目的が達成されなくなります。
関連
-
[解決済み】このアクティビティでは、Theme.AppCompatテーマ(またはその子孫)を使用する必要があります。
-
[解決済み】Android ADB デバイスがオフラインで、コマンドを発行できない。
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み】このアクティビティは、すでにウィンドウ装飾によって提供されるアクションバーを持っています。
-
[解決済み】"ビットマップが大きすぎてテクスチャにアップロードできない"
-
[解決済み】Android Studio 3.2 - com.android.tools.build:aapt2:3.2.0-4818971 を見つけられませんでした。
-
[解決済み】'dependencies' を '(groovy.lang.Closure)' に適用できない。)
-
[解決済み】IllegalStateException: ViewPager で onSaveInstanceState の後にこのアクションを実行できません。
-
[解決済み】android.content.res.Resources$NotFoundExceptionの取得:androidにリソースが存在する場合でも例外が発生する。
-
[解決済み] setBackgroundDrawable() 非推奨
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】まだ警告が出る:設定 'compile' は時代遅れで 'implementation' に置き換わった。
-
[解決済み】AndroidのSSL接続でトラストアンカーが見つからない
-
[解決済み】Androidエミュレータのエラーメッセージ。"PANIC: Missing emulator engine program for 'x86' CPUS." (パニック: エミュレータ・エンジン・プログラムがありません)
-
[解決済み】アンドロイドクロームブラウザのモバイルウェブアプリケーションのメニューでHTMLユニコード ☰が検出されない。
-
[解決済み】プロガードを有効にすると、タスク ':app:crashlyticsStoreDeobsDebug' の依存関係を判断できない。
-
[解決済み】カメラサービスへの接続に失敗しました。
-
[解決済み】フラグメントMyFragmentがアクティビティにアタッチされない。
-
[解決済み】アクティビティにない場所でのgetLayoutInflater()の呼び出し
-
[解決済み] 複数のデバイスを接続しているときにADB Shellを使用するには?error: more than one device and emulator "で失敗します。
-
[解決済み] APKのインストール中にDELETE_FAILED_INTERNAL_ERRORエラーが発生する。