Android“只有创建视图层次结构的原始线程才能触摸其视图." [英] Android "Only the original thread that created a view hierarchy can touch its views."

查看:33
本文介绍了Android“只有创建视图层次结构的原始线程才能触摸其视图."的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Android 中构建了一个简单的音乐播放器.每首歌曲的视图都包含一个 SeekBar,实现如下:

I've built a simple music player in Android. The view for each song contains a SeekBar, implemented like this:

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,在 onCreate() 中用 findViewById() 得到它,然后把它放在 run()progress.setProgress(pos) 之后:

This works fine. Now I want a timer counting the seconds/minutes of the progress of the song. So I put a TextView in the layout, get it with findViewById() in onCreate(), and put this in run() after 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);

但最后一行给了我一个例外:

But that last line gives me the exception:

android.view.ViewRoot$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图.

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

然而,我在这里做的事情与使用 SeekBar 所做的基本相同 - 在 onCreate 中创建视图,然后在 run 中触摸它() - 它没有给我这个抱怨.

Yet I'm doing basically the same thing here as I'm doing with the SeekBar - creating the view in onCreate, then touching it in run() - and it doesn't give me this complaint.

推荐答案

您必须将更新 UI 的后台任务部分移到主线程上.有一段简单的代码:

You have to move the portion of the background task that updates the UI onto the main thread. There is a simple piece of code for this:

runOnUiThread(new Runnable() {

    @Override
    public void run() {

        // Stuff that updates the UI

    }
});

Activity 的文档.runOnUiThread.

只需将其嵌套在后台运行的方法中,然后将实现任何更新的代码复制粘贴到块中间.仅包含尽可能少的代码,否则您将开始违背后台线程的目的.

Just nest this inside the method that is running in the background, and then copy paste the code that implements any updates in the middle of the block. Include only the smallest amount of code possible, otherwise you start to defeat the purpose of the background thread.

这篇关于Android“只有创建视图层次结构的原始线程才能触摸其视图."的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆