Saya telah membangun pemutar musik sederhana di Android. Tampilan untuk setiap lagu berisi SeekBar, diimplementasikan seperti ini:
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);
}
}
Ini berfungsi dengan baik. Sekarang saya ingin penghitung waktu menghitung detik / menit dari kemajuan lagu. Jadi saya menaruh TextView
di tata letak, mendapatkannya dengan findViewById()
di onCreate()
, dan menempatkan ini dalam run()
setelah 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);
Tapi kalimat terakhir itu memberi saya pengecualian:
android.view.ViewRoot $ CalledFromWrongThreadException: Hanya utas asli yang membuat hierarki tampilan yang dapat menyentuh pandangannya.
Namun pada dasarnya saya melakukan hal yang sama di sini seperti yang saya lakukan dengan SeekBar
- membuat tampilan masuk onCreate
, kemudian menyentuhnya run()
- dan itu tidak memberi saya keluhan ini.
sumber
error.setText(res.toString());
inside the run (), tapi saya tidak bisa menggunakan res karena itu belum final .. terlalu burukmyActivityObject.runOnUiThread(etc)
runOnUiThread()
adalah metode Kegiatan. Saya menjalankan kode saya dalam sebuah fragmen. Saya akhirnya melakukangetActivity().runOnUiThread(etc)
dan berhasil. Fantastis!;Saya memecahkan ini dengan memasukkan ke
runOnUiThread( new Runnable(){ ..
dalamrun()
:sumber
wait(5000);
tidak ada di dalam Runnable, jika tidak UI Anda akan membeku selama periode tunggu. Anda harus mempertimbangkan untuk menggunakanAsyncTask
Utas untuk operasi seperti ini.Solusi saya untuk ini:
Panggil metode ini di utas latar belakang.
sumber
runOnUiThread
denganrunTestOnUiThread
. Terima kasihBiasanya, tindakan apa pun yang melibatkan antarmuka pengguna harus dilakukan di utas utama atau UI, yaitu tindakan di mana
onCreate()
dan penanganan peristiwa dieksekusi. Salah satu cara untuk memastikannya adalah menggunakan runOnUiThread () , yang lain adalah menggunakan Handler.ProgressBar.setProgress()
memiliki mekanisme yang akan selalu dijalankan pada utas utama, jadi itu sebabnya ia bekerja.Lihat Threading Tanpa Rasa Sakit .
sumber
Saya sudah dalam situasi ini, tetapi saya menemukan solusi dengan Object Handler.
Dalam kasus saya, saya ingin memperbarui ProgressDialog dengan pola pengamat . Pandangan saya mengimplementasikan pengamat dan mengganti metode pembaruan.
Jadi, utas utama saya membuat tampilan dan utas lainnya memanggil metode pembaruan yang memperbarui ProgressDialop dan ....:
Dimungkinkan untuk menyelesaikan masalah dengan Object Handler.
Di bawah ini, berbagai bagian kode saya:
Penjelasan ini dapat ditemukan di halaman ini , dan Anda harus membaca "Contoh ProgressDialog dengan utas kedua".
sumber
Anda dapat menggunakan Handler untuk Menghapus Tampilan tanpa mengganggu Utas UI utama. Berikut ini contoh kode
sumber
Saya melihat bahwa Anda telah menerima jawaban @ providence. Untuk jaga-jaga, Anda juga dapat menggunakan pawang juga! Pertama, lakukan bidang int.
Selanjutnya, buat instance handler sebagai bidang.
Buat metode.
Akhirnya, letakkan ini di
onCreate()
metode.sumber
Saya memiliki masalah serupa, dan solusi saya jelek, tetapi berhasil:
sumber
Saya gunakan
Handler
denganLooper.getMainLooper()
. Ini bekerja dengan baik untukku.sumber
Gunakan kode ini, dan tidak perlu
runOnUiThread
berfungsi:sumber
Ini secara eksplisit melempar kesalahan. Ia mengatakan utas mana saja yang menciptakan tampilan, hanya yang bisa menyentuh pandangannya. Itu karena tampilan yang dibuat ada di dalam ruang utas itu. Pembuatan view (GUI) terjadi di utas UI (utama). Jadi, Anda selalu menggunakan utas UI untuk mengakses metode tersebut.
Pada gambar di atas, variabel progres berada di dalam ruang utas UI. Jadi, hanya utas UI yang dapat mengakses variabel ini. Di sini, Anda mengakses kemajuan melalui Thread baru (), dan itulah sebabnya Anda mendapat kesalahan.
sumber
Ini terjadi pada saya ketika saya meminta perubahan UI dari
doInBackground
dariAsynctask
alih-alih menggunakanonPostExecute
.Berurusan dengan UI dalam
onPostExecute
memecahkan masalah saya.sumber
onPostExecute
ini juga merupakan metodeAsyncTask
tetapi berjalan pada utas UI. Lihat di sini: blog.teamtreehouse.com/all-about-android-asynctasksKotlin coroutine dapat membuat kode Anda lebih ringkas dan mudah dibaca seperti ini:
Atau sebaliknya:
sumber
Saya bekerja dengan kelas yang tidak mengandung referensi ke konteksnya. Jadi tidak mungkin bagi saya untuk menggunakan yang
runOnUIThread();
saya gunakanview.post();
dan itu diselesaikan.sumber
audioMessage
dantvPlayDuration
dengan kode pertanyaan?audioMessage
adalah objek penahan tampilan teks.tvPlayDuration
adalah tampilan teks yang ingin kami perbarui dari utas non UI. Dalam pertanyaan di atas,currentTime
apakah tampilan teks tetapi tidak memiliki objek pemegang.Saat menggunakan AsyncTask Perbarui UI dalam metode onPostExecute
sumber
Saya menghadapi masalah yang sama dan tidak ada metode yang disebutkan di atas bekerja untuk saya. Pada akhirnya, ini berhasil bagi saya:
Saya menemukan permata ini di sini .
sumber
Ini adalah jejak tumpukan pengecualian yang disebutkan
Jadi jika Anda pergi dan menggali maka Anda akan tahu
Di mana mThread diinisialisasi dalam konstruktor seperti di bawah ini
Yang ingin saya katakan adalah ketika kami membuat tampilan tertentu, kami membuatnya di UI Thread dan kemudian mencoba untuk memodifikasi di Worker Thread.
Kami dapat memverifikasinya melalui cuplikan kode di bawah ini
saat kami mengembang tata letak dan nanti di mana Anda mendapatkan pengecualian.
sumber
Jika Anda tidak ingin menggunakan
runOnUiThread
API, Anda sebenarnya dapat menerapkanAsynTask
untuk operasi yang membutuhkan beberapa detik untuk menyelesaikannya. Tetapi dalam hal itu, juga setelah memproses pekerjaandoinBackground()
Anda, Anda harus mengembalikan tampilan yang telah selesaionPostExecute()
. Implementasi Android memungkinkan hanya utas UI utama untuk berinteraksi dengan tampilan.sumber
Jika Anda hanya ingin membatalkan (fungsi panggil ulang / redraw) dari Thread non UI Anda, gunakan postInvalidate ()
Ini akan mengirim permintaan yang tidak valid pada utas UI.
Untuk informasi lebih lanjut: apa-apa-postinvalidate-do
sumber
Bagi saya masalahnya adalah bahwa saya menelepon
onProgressUpdate()
secara eksplisit dari kode saya. Ini seharusnya tidak dilakukan. Saya meneleponpublishProgress()
sebaliknya dan itu menyelesaikan kesalahan.sumber
Dalam kasus saya, saya punya
EditText
di Adapter, dan itu sudah ada di utas UI. Namun, ketika Kegiatan ini dimuat, itu crash dengan kesalahan ini.Solusi saya adalah saya harus menghapus
<requestFocus />
dari EditText dalam XML.sumber
Untuk orang-orang yang berjuang di Kotlin, kerjanya seperti ini:
sumber
Dipecahkan: Masukkan metode ini ke dalam doInBackround Class ... dan sampaikan pesannya
sumber
Dalam kasus saya, pemanggil memanggil terlalu banyak kali dalam waktu singkat akan mendapatkan kesalahan ini, saya hanya menempatkan waktu berlalu memeriksa untuk tidak melakukan apa-apa jika terlalu pendek, misalnya mengabaikan jika fungsi dipanggil kurang dari 0,5 detik:
sumber
Jika Anda tidak dapat menemukan UIThread, Anda dapat menggunakan cara ini.
maksud kontekscurrent Anda, Anda harus menguraikan Konteks Saat Ini
sumber
Kita harus menggunakan Thread UI untuk pekerjaan dengan cara yang benar. Kita dapat menggunakan Thread UI di Kotlin:
@canerkaseler
sumber
Di Kotlin cukup masukkan kode Anda dalam metode aktivitas runOnUiThread
sumber