Criei um player de música simples no Android. A visualização de cada música contém uma SeekBar, implementada assim:
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);
}
}
Isso funciona bem. Agora eu quero um cronômetro contando os segundos / minutos do andamento da música. Então eu coloquei um TextView
no layout, obtê-lo com findViewById()
no onCreate()
, e colocar isso em run()
depois 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);
Mas essa última linha me dá a exceção:
android.view.ViewRoot $ CalledFromWrongThreadException: Somente o encadeamento original que criou uma hierarquia de exibição pode tocar em suas exibições.
No entanto, estou fazendo basicamente a mesma coisa que estou fazendo com SeekBar
- criando a visualização onCreate
e depois tocando-a run()
- e isso não me causa essa reclamação.
fonte
error.setText(res.toString());
dentro do método run (), mas eu não poderia usar os res porque não era definitiva .. muito ruimmyActivityObject.runOnUiThread(etc)
runOnUiThread()
é um método de Atividade. Eu estava executando meu código em um fragmento. Acabei fazendogetActivity().runOnUiThread(etc)
e funcionou. Fantástico!;Eu resolvi isso colocando
runOnUiThread( new Runnable(){ ..
dentrorun()
:fonte
wait(5000);
não está dentro do Runnable; caso contrário, sua interface do usuário congelará durante o período de espera. Você deve considerar o usoAsyncTask
do Thread em vez de operações como estas.Minha solução para isso:
Chame esse método em um encadeamento em segundo plano.
fonte
runOnUiThread
porrunTestOnUiThread
. GraçasGeralmente, qualquer ação que envolva a interface do usuário deve ser realizada no encadeamento principal ou da interface do usuário, que é aquele em que a
onCreate()
manipulação de eventos é executada. Uma maneira de ter certeza disso é usando runOnUiThread () , outra é usar Handlers.ProgressBar.setProgress()
possui um mecanismo para o qual sempre será executado no encadeamento principal, e é por isso que funcionou.Consulte Rosqueamento indolor .
fonte
Estive nessa situação, mas encontrei uma solução com o objeto manipulador.
No meu caso, quero atualizar um ProgressDialog com o padrão observador . Minha visão implementa o observador e substitui o método de atualização.
Portanto, meu thread principal cria a view e outro thread chama o método update que atualiza o ProgressDialop e ....:
É possível resolver o problema com o objeto manipulador.
Abaixo, diferentes partes do meu código:
Esta explicação pode ser encontrada nesta página e você deve ler o "Exemplo ProgressDialog com um segundo thread".
fonte
Você pode usar o manipulador para excluir a exibição sem perturbar o principal thread da interface do usuário. Aqui está o código de exemplo
fonte
Vejo que você aceitou a resposta da providência. Apenas no caso, você também pode usar o manipulador! Primeiro, faça os campos int.
Em seguida, crie uma instância de manipulador como um campo.
Faça um método.
Por fim, coloque isso no
onCreate()
métodofonte
Eu tive um problema semelhante e minha solução é feia, mas funciona:
fonte
Eu uso
Handler
comLooper.getMainLooper()
. Funcionou bem para mim.fonte
Use este código e não há necessidade de
runOnUiThread
funcionar:fonte
Isso está explicitamente gerando um erro. Ele diz que qualquer segmento que criou uma visualização, apenas que pode tocar em suas visualizações. Isso ocorre porque a visualização criada está dentro do espaço desse segmento. A criação da visualização (GUI) ocorre no encadeamento da interface do usuário (principal). Portanto, você sempre usa o thread da interface do usuário para acessar esses métodos.
Na imagem acima, a variável progress está dentro do espaço do thread da interface do usuário. Portanto, apenas o thread da interface do usuário pode acessar essa variável. Aqui, você está acessando o progresso por meio do novo Thread () e é por isso que ocorreu um erro.
fonte
Isso aconteceu quando pedi uma alteração na interface do usuário de um
doInBackground
de emAsynctask
vez de usaronPostExecute
.Lidar com a interface do usuário
onPostExecute
resolveu meu problema.fonte
onPostExecute
também é um método de,AsyncTask
mas é executado no thread da interface do usuário. Veja aqui: blog.teamtreehouse.com/all-about-android-asynctasksAs corotinas da Kotlin podem tornar seu código mais conciso e legível assim:
Ou vice-versa:
fonte
Eu estava trabalhando com uma classe que não continha uma referência ao contexto. Portanto, não foi possível usar o que
runOnUIThread();
eu useiview.post();
e foi resolvido.fonte
audioMessage
etvPlayDuration
o código das perguntas?audioMessage
é um objeto titular da exibição de texto.tvPlayDuration
é a exibição de texto que queremos atualizar a partir de um thread que não seja da interface do usuário. Na pergunta acima,currentTime
é a exibição de texto, mas ela não possui um objeto titular.Ao usar o AsyncTask, atualize a interface do usuário no método onPostExecute
fonte
Eu estava enfrentando um problema semelhante e nenhum dos métodos mencionados acima funcionou para mim. No final, isso fez o truque para mim:
Encontrei esta jóia aqui .
fonte
Este é o rastreamento de pilha da exceção mencionada
Então, se você vai cavar, então você vem a saber
Onde mThread é inicializado no construtor como abaixo
Tudo o que quero dizer é que, quando criamos uma visualização específica, a criamos no UI Thread e, posteriormente, tentamos modificar em um Worker Thread.
Podemos verificá-lo através do snippet de código abaixo
quando inflamos o layout e mais tarde onde você está recebendo exceção.
fonte
Se você não deseja usar a
runOnUiThread
API, é possível implementarAsynTask
as operações que levam alguns segundos para serem concluídas. Mas, nesse caso, também após o processamento do seu trabalhodoinBackground()
, é necessário retornar a exibição concluídaonPostExecute()
. A implementação do Android permite que apenas o principal thread da interface do usuário interaja com as visualizações.fonte
Se você simplesmente deseja invalidar (função de repintar / redesenhar chamadas) do seu Thread não UI, use postInvalidate ()
Isso postará uma solicitação inválida no thread da interface do usuário.
Para mais informações: what-does-postinvalidate-do
fonte
Para mim, o problema era que eu estava ligando
onProgressUpdate()
explicitamente do meu código. Isso não deve ser feito. Eu ligueipublishProgress()
e isso resolveu o erro.fonte
No meu caso, eu tenho
EditText
no Adapter, e ele já está no thread da interface do usuário. No entanto, quando esta atividade é carregada, ela falha com esse erro.Minha solução é que preciso remover
<requestFocus />
o EditText em XML.fonte
Para as pessoas que lutam em Kotlin, funciona assim:
fonte
Resolvido: basta colocar esse método na classe doInBackround ... e passar a mensagem
fonte
No meu caso, o chamador muitas vezes em pouco tempo receberá esse erro, basta colocar a verificação do tempo decorrido para não fazer nada se for muito curto, por exemplo, ignore se a função for chamada em menos de 0,5 segundo:
fonte
Se você não conseguiu encontrar um UIThread, pode usar desta maneira.
se seu contexto atual significa, você precisa analisar o Contexto Atual
fonte
Temos que usar o UI Thread para o trabalho da maneira correta. Podemos usar o Thread da interface do usuário no Kotlin:
@canerkaseler
fonte
No Kotlin, basta colocar seu código no método de atividade runOnUiThread
fonte