Возможно (если маловероятно), что у вас есть старая версия OneSignal, где synchronized void startDelayedWrite()
не synchronized
. В этом случае я бы обновил, и посмотреть, исправит ли это вещи. Если не видите следующее:
Здесь возникает указанное исключение:
synchronized void startDelayedWrite() {
if (mHandler == null) {
start();
mHandler = new Handler(getLooper());
}
//rest of function irrelevant.
В Javado c для Thread.start
указано следующее:
Никогда не разрешено начинать поток более одного раза. В частности, поток не может быть перезапущен после завершения выполнения.
Исходя из этого и реализации Thread.start
, мы можем сделать вывод, что рассматриваемый поток запускается дважды.
Для this
, запускаемого дважды в startDelayedWrite
, new Handler(getLooper())
необходимо вызвать исключение, в противном случае мы не будем вводить это, если оператор снова. Я не вижу способа для getLooper()
вызвать исключение, но new Handler
, конечно, может, если getLooper()
равно нулю.
Реализация getLooper()
выглядит следующим образом:
public Looper getLooper() {
if (!isAlive()) {
return null;
}
//rest omitted b/c irrelevant
Единственный способ, которым мог завершиться рассматриваемый поток, это если Thread.run
завершился раньше.
Реализация выполнения потока выглядит следующим образом:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
Looper.loop
, предназначена для того, чтобы быть полубесконечным l oop, который читает из очереди сообщений.
Обратите внимание на следующее в Looper.loop
:
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
Так что если msg == null
, то наш поток завершается быстро, что может вызвать исключение в mHandler = new Handler(getLooper());
, в результате чего Thread.start
будет звонил дважды.
Есть и другие правдоподобные объяснения. Например, возможно, что Looper.loop
аварийно завершится в некоторой более ранней точке.
Чтобы смягчить это, я бы добавил блок try{} finally{}
вокруг mHandler = new Handler(getLooper());
, чтобы обработать случай, когда Looper
уже вышел. В качестве альтернативы я могу ошибаться, и это состояние гонки может быть вызвано чем-то совершенно другим.