J'ai construit un simple lecteur de musique sous Android. La vue de chaque chanson contient un SeekBar, implémenté comme ceci:
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);
}
}
Cela fonctionne bien. Maintenant, je veux une minuterie comptant les secondes / minutes de la progression de la chanson. Donc , je mets un TextView
dans la mise en page, obtenir avec findViewById()
dans onCreate()
et mettre cela en run()
après 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);
Mais cette dernière ligne me donne l'exception:
android.view.ViewRoot $ CalledFromWrongThreadException: seul le thread d'origine qui a créé une hiérarchie de vues peut toucher ses vues.
Pourtant, je fais essentiellement la même chose ici que je fais avec le SeekBar
- créer la vue dans onCreate
, puis la toucher run()
- et cela ne me donne pas cette plainte.
la source
error.setText(res.toString());
méthode à l'intérieur de la méthode run (), mais je ne pouvais pas utiliser le res car ce n'était pas final .. dommagemyActivityObject.runOnUiThread(etc)
runOnUiThread()
c'était une méthode d'activité. J'exécutais mon code dans un fragment. J'ai fini par fairegetActivity().runOnUiThread(etc)
et ça a marché. Fantastique!;J'ai résolu cela en mettant à l'
runOnUiThread( new Runnable(){ ..
intérieurrun()
:la source
wait(5000);
ne se trouve pas dans Runnable, sinon votre interface utilisateur se figera pendant la période d'attente. Vous devriez envisager d'utiliser à laAsyncTask
place de Thread pour des opérations comme celles-ci.Ma solution à cela:
Appelez cette méthode sur un thread d'arrière-plan.
la source
runOnUiThread
parrunTestOnUiThread
. MerciHabituellement, toute action impliquant l'interface utilisateur doit être effectuée dans le thread principal ou d'interface utilisateur, c'est-à-dire celui dans lequel la
onCreate()
gestion des événements est exécutée. Une façon de s'en assurer est d'utiliser runOnUiThread () , une autre utilise des gestionnaires.ProgressBar.setProgress()
a un mécanisme pour lequel il s'exécutera toujours sur le thread principal, c'est pourquoi cela a fonctionné.Voir Filetage sans douleur .
la source
J'ai été dans cette situation, mais j'ai trouvé une solution avec l'objet gestionnaire.
Dans mon cas, je veux mettre à jour un ProgressDialog avec le modèle d'observateur . Ma vue implémente l'observateur et remplace la méthode de mise à jour.
Donc, mon thread principal crée la vue et un autre thread appelle la méthode de mise à jour qui met à jour ProgressDialop et ....:
Il est possible de résoudre le problème avec l'objet gestionnaire.
Ci-dessous, différentes parties de mon code:
Cette explication se trouve sur cette page , et vous devez lire "Exemple ProgressDialog avec un deuxième fil".
la source
Vous pouvez utiliser le gestionnaire pour supprimer la vue sans perturber le thread d'interface utilisateur principal. Voici un exemple de code
la source
Je vois que vous avez accepté la réponse de @ providence. Au cas où, vous pouvez également utiliser le gestionnaire! Tout d'abord, faites les champs int.
Ensuite, créez une instance de gestionnaire en tant que champ.
Faites une méthode.
Enfin, mettez cela à la
onCreate()
méthode.la source
J'ai eu un problème similaire, et ma solution est moche, mais cela fonctionne:
la source
J'utilise
Handler
avecLooper.getMainLooper()
. Cela a bien fonctionné pour moi.la source
Utilisez ce code, et pas besoin de
runOnUiThread
fonctionner:la source
Cela renvoie explicitement une erreur. Il indique quel que soit le thread qui a créé une vue, seul celui qui peut toucher ses vues. C'est parce que la vue créée est à l'intérieur de l'espace de ce thread. La création de la vue (GUI) se produit dans le thread UI (principal). Ainsi, vous utilisez toujours le thread d'interface utilisateur pour accéder à ces méthodes.
Dans l'image ci-dessus, la variable de progression se trouve à l'intérieur de l'espace du thread d'interface utilisateur. Ainsi, seul le thread d'interface utilisateur peut accéder à cette variable. Ici, vous accédez à la progression via le nouveau Thread (), et c'est pourquoi vous avez une erreur.
la source
Cela est arrivé à mon quand j'ai appelé pour un changement d'interface utilisateur à partir d'un
doInBackground
auAsynctask
lieu d'utiliseronPostExecute
.Gérer l'interface utilisateur a
onPostExecute
résolu mon problème.la source
onPostExecute
c'est aussi une méthode deAsyncTask
mais elle s'exécute sur le thread d'interface utilisateur. Voir ici: blog.teamtreehouse.com/all-about-android-asynctasksLes coroutines Kotlin peuvent rendre votre code plus concis et lisible comme ceci:
Ou vice versa:
la source
Je travaillais avec une classe qui ne contenait aucune référence au contexte. Il ne m'a donc pas été possible d'utiliser ce que
runOnUIThread();
j'ai utiliséview.post();
et cela a été résolu.la source
audioMessage
ettvPlayDuration
au code des questions?audioMessage
est un objet support de la vue texte.tvPlayDuration
est la vue texte que nous voulons mettre à jour à partir d'un thread non UI. Dans la question ci-dessus,currentTime
est la vue texte mais elle n'a pas d'objet support.Lors de l'utilisation de AsyncTask Mettre à jour l'interface utilisateur dans la méthode onPostExecute
la source
J'étais confronté à un problème similaire et aucune des méthodes mentionnées ci-dessus ne fonctionnait pour moi. En fin de compte, cela a fait l'affaire pour moi:
J'ai trouvé ce bijou ici .
la source
Ceci est la trace de pile de l'exception mentionnée
Donc, si vous allez creuser, vous découvrez
Où mThread est initialisé dans le constructeur comme ci-dessous
Tout ce que je veux dire, c'est que lorsque nous avons créé une vue particulière, nous l'avons créée sur le thread d'interface utilisateur et essayons plus tard de la modifier dans un thread de travail.
Nous pouvons le vérifier via l'extrait de code ci-dessous
lorsque nous gonflons la mise en page et plus tard où vous obtenez une exception.
la source
Si vous ne souhaitez pas utiliser l'
runOnUiThread
API, vous pouvez en fait l'implémenterAsynTask
pour les opérations qui prennent quelques secondes à terminer. Mais dans ce cas, également après avoir traité votre travaildoinBackground()
, vous devez renvoyer la vue terminée dansonPostExecute()
. L'implémentation Android permet uniquement au thread d'interface utilisateur principal d'interagir avec les vues.la source
Si vous souhaitez simplement invalider (appeler la fonction repeindre / redessiner) à partir de votre thread non UI, utilisez postInvalidate ()
Cela affichera une demande d'invalidation sur le thread d'interface utilisateur.
Pour plus d'informations: what-does-postinvalidate-do
la source
Pour moi, le problème était que j'appelais
onProgressUpdate()
explicitement à partir de mon code. Cela ne devrait pas être fait. J'ai appelé à lapublishProgress()
place et cela a résolu l'erreur.la source
Dans mon cas, j'ai
EditText
dans l'adaptateur, et c'est déjà dans le thread d'interface utilisateur. Cependant, lorsque cette activité se charge, elle se bloque avec cette erreur.Ma solution est que je dois supprimer
<requestFocus />
de EditText en XML.la source
Pour les personnes en difficulté à Kotlin, cela fonctionne comme ceci:
la source
Résolu: Mettez simplement cette méthode dans la classe doInBackround ... et passez le message
la source
Dans mon cas, l'appelant appelle trop de fois en peu de temps obtiendra cette erreur, j'ai simplement mis la vérification du temps écoulé pour ne rien faire si trop court, par exemple ignorer si la fonction est appelée moins de 0,5 seconde:
la source
Si vous ne parvenez pas à trouver un UIThread, vous pouvez utiliser cette méthode.
votre contexte actuel signifie que vous devez analyser le contexte actuel
la source
Nous devons utiliser UI Thread pour le travail avec vrai chemin. Nous pouvons utiliser UI Thread dans Kotlin:
@canerkaseler
la source
Dans Kotlin, mettez simplement votre code dans la méthode d'activité runOnUiThread
la source