【问题标题】:Calling Looper.prepare() in a thread's constructor results in RunTimeException在线程的构造函数中调用 Looper.prepare() 会导致 RunTimeException
【发布时间】:2017-09-26 16:57:53
【问题描述】:

我有一个class 延伸到Thread 如下 -

public class ThreadTest extends Thread {

    private Handler handler;
    private Runnable runnable;

    public ThreadTest(Runnable runnable, Handler handler) {

        this.handler = handler;
        this.runnable = runnable;
    }

    @Override
    public void run() {
        super.run();

        Message msg = handler.obtainMessage();
        msg.obj = "YUSSSSSS!";
        handler.sendMessage(msg);

        if (Looper.myLooper() != null) {
            Looper.myLooper().quit();
            Log.i("Looper", "has been quit");
        }

    }
}

现在,我想在这个帖子上附加一个looper。根据我对Looper 的理解,默认情况下,只有主线程会附加一个looper

我尝试像这样调用Looper.prepare()Looper.loop() 构成ThreadTest 类的构造函数 -

public ThreadTest(Runnable runnable, Handler handler) {

        Looper.prepare();

        this.handler = handler;
        this.runnable = runnable;

        Looper.loop();
    }

但是,我在Looper.prepare(); 得到了java.lang.RuntimeException: Only one Looper may be created per thread 异常。

虽然,如果我在Run() 中附加looper,我不会遇到任何问题。

我做错了什么?

【问题讨论】:

  • @pskink 在哪里?当我在构造函数上调用Looper.prepare() 时,我不会在run() 下调用它。
  • @pskink 我只是在玩 Android 中的多任务处理。我从不调用 prepare() 两次。因此,这个问题。
  • 这是因为您在主 UI 线程(在 ThreadTest 构造函数内)调用 Looper#prepare,它已经附加了 Looper
  • @pskink 有道理。

标签: java android multithreading android-thread


【解决方案1】:

每个线程都有一个looper,并且只有一个looper,您需要在尝试将looper添加到线程之前进行检查。

您还需要在构造函数中添加if (Looper.myLooper() != null) {}。 记住looper.myLooper()只能在线程构造函数中调用它才能获得主线程Looper。因为那个时候新线程还没有构造出来。

【讨论】:

    【解决方案2】:

    当您在构造函数中调用Looper.prepare() 时,实际上是通过调用其构造函数(您没有指定,但我猜是主线程)从创建对象的任何其他线程调用它,但run() 方法从线程本身调用。所以你应该把你的looper附在run()中。

    要调用run(),您必须调用Thread.start(),并且不能保证在您调用start() 后会立即调用run(),所以如果您希望looper 在之后立即可用调用构造函数,你可以在构造函数中等待直到run()被调用,然后notify()构造函数中的等待线程是这样的:

    public class ThreadTest extends Thread
    {
        public ThreadTest()
        {
            //init...
    
            //wait until thread has started
            waitForRun();
        }
    
        private void waitForRun()
        {
            try
            {
                synchronized (this)
                {
                    start();
                    wait();
                }
            }
            catch (InterruptedException ignored)
            {
                
            }
        }
    
        @Override
        public void run()
        {
            Looper.prepare();
            synchronized (this)
            {
                //notify the waiting thread in the constructor that this thread
                //has started and has a looper
                notifyAll();
            }
    
            //do stuff...
    
            Looper.loop();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 2020-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多