Я построил простой музыкальный проигрыватель в 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()
- и это не вызывает у меня жалобы.
источник
error.setText(res.toString());
метод run () внутри, но я не мог использовать res, потому что он не был окончательным ... очень плохоmyActivityObject.runOnUiThread(etc)
runOnUiThread()
это метод Деятельности. Я выполнял свой код во фрагменте. Я закончил тем, что делал,getActivity().runOnUiThread(etc)
и это работало. Фантастический!;Я решил это, вставив
runOnUiThread( new Runnable(){ ..
внутрьrun()
:источник
wait(5000);
он не находится внутри Runnable, иначе ваш пользовательский интерфейс будет зависать в течение периода ожидания. Вы должны рассмотреть возможность использованияAsyncTask
вместо Thread для таких операций.Мое решение этого:
Вызовите этот метод в фоновом потоке.
источник
runOnUiThread
наrunTestOnUiThread
. СпасибоОбычно любое действие, связанное с пользовательским интерфейсом, должно выполняться в основном потоке или потоке пользовательского интерфейса, то есть в том, в котором
onCreate()
выполняется обработка событий. Один из способов убедиться в этом - использовать runOnUiThread () , другой - использовать обработчики.ProgressBar.setProgress()
имеет механизм, который он всегда будет выполнять в основном потоке, поэтому он работал.См. Безболезненная нить .
источник
Я был в этой ситуации, но я нашел решение с помощью объекта Handler.
В моем случае я хочу обновить ProgressDialog с помощью шаблона наблюдателя . Мой взгляд реализует наблюдателя и переопределяет метод обновления.
Итак, мой основной поток создает представление, а другой поток вызывает метод update, который обновляет ProgressDialop и ....:
Возможно решить проблему с Объектом Обработчика.
Ниже приведены различные части моего кода:
Это объяснение можно найти на этой странице , и вы должны прочитать «Пример ProgressDialog со вторым потоком».
источник
Вы можете использовать Handler для удаления вида, не нарушая основной поток пользовательского интерфейса. Вот пример кода
источник
Я вижу, что вы приняли ответ @ провидения. На всякий случай, вы также можете использовать обработчик тоже! Сначала сделайте поля int.
Затем создайте экземпляр обработчика как поле.
Сделай метод.
Наконец, поместите это в
onCreate()
метод.источник
У меня была похожая проблема, и мое решение некрасиво, но оно работает:
источник
Я использую
Handler
сLooper.getMainLooper()
. Это работало хорошо для меня.источник
Используйте этот код, и не нужно
runOnUiThread
функционировать:источник
Это явно выдает ошибку. В нем говорится, какой поток создал вид, только тот, который может касаться его. Это потому, что созданный вид находится внутри пространства этого потока. Создание представления (GUI) происходит в потоке пользовательского интерфейса (основного). Таким образом, вы всегда используете поток пользовательского интерфейса для доступа к этим методам.
На рисунке выше переменная прогресса находится внутри пространства потока пользовательского интерфейса. Таким образом, только поток пользовательского интерфейса может получить доступ к этой переменной. Здесь вы получаете доступ к прогрессу через новую Thread (), и именно поэтому вы получили ошибку.
источник
Это случилось с моим , когда я назвал для изменения пользовательского интерфейса из
doInBackground
изAsynctask
вместо того , чтобы использоватьonPostExecute
.Работа с пользовательским интерфейсом
onPostExecute
решает мою проблему.источник
onPostExecute
это также метод,AsyncTask
но он работает в потоке пользовательского интерфейса. Смотрите здесь: blog.teamtreehouse.com/all-about-android-asynctasksСопрограммы Kotlin могут сделать ваш код более кратким и читабельным, например:
Или наоборот:
источник
Я работал с классом, который не содержал ссылку на контекст. Так что я не мог использовать,
runOnUIThread();
я использовал,view.post();
и это было решено.источник
audioMessage
иtvPlayDuration
с кодом вопросы?audioMessage
является объектом-держателем текстового представления.tvPlayDuration
это текстовое представление, которое мы хотим обновить из не-пользовательского интерфейса. В приведенном выше вопросеcurrentTime
текстовое представление, но у него нет объекта-держателя.При использовании AsyncTask обновите интерфейс в методе onPostExecute
источник
Я столкнулся с подобной проблемой, и ни один из методов, упомянутых выше, не помог мне. В конце концов, это помогло мне:
Я нашел этот драгоценный камень здесь .
источник
Это трассировка стека упомянутого исключения
Так что, если вы идете копать, то вы узнаете,
Где mThread инициализируется в конструкторе, как показано ниже
Все, что я хочу сказать, это то, что когда мы создавали конкретное представление, мы создавали его в потоке пользовательского интерфейса, а затем пытались изменить его в рабочем потоке.
Мы можем проверить это через приведенный ниже фрагмент кода
когда мы раздуваем макет и позже, где вы получаете исключение.
источник
Если вы не хотите использовать
runOnUiThread
API, вы можете реализоватьAsynTask
операции, выполнение которых занимает несколько секунд. Но в этом случае, также после обработки вашей работыdoinBackground()
, вам нужно вернуть законченный вид вonPostExecute()
. Реализация Android позволяет только основным потокам пользовательского интерфейса взаимодействовать с представлениями.источник
Если вы просто хотите сделать недействительной (вызвать функцию перерисовки / перерисовки) из вашей ветки, не связанной с пользовательским интерфейсом, используйте postInvalidate ()
Это опубликует недействительный запрос в UI-потоке.
Для получения дополнительной информации: что-делает-postinvalidate-do
источник
Для меня проблема была в том, что я звонил
onProgressUpdate()
явно из своего кода. Это не должно быть сделано. Я звонилpublishProgress()
вместо этого, и это решило ошибку.источник
В моем случае у меня есть
EditText
в адаптере, и это уже в потоке пользовательского интерфейса. Однако при загрузке этого действия происходит сбой с этой ошибкой.Мое решение - мне нужно удалить
<requestFocus />
из EditText в XML.источник
Для людей, борющихся в Котлине, это работает так:
источник
Решено: Просто поместите этот метод в класс doInBackround ... и передайте сообщение
источник
В моем случае вызывающий вызов слишком много раз за короткое время получит эту ошибку, я просто помещаю проверку истекшего времени, чтобы ничего не делать, если она слишком короткая, например игнорировать, если функция вызывается менее чем за 0,5 секунды:
источник
Если вы не смогли найти UIThread, вы можете использовать этот способ.
yourcurrentcontext означает, что вам нужно проанализировать текущий контекст
источник
Мы должны использовать UI Thread для правильной работы. Мы можем использовать UI Thread в Kotlin:
@canerkaseler
источник
В Kotlin просто поместите ваш код в метод активности runOnUiThread
источник