下面的异常是什么意思;我该怎么解决呢?
这是代码:
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
这是例外:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.widget.Toast.<init>(Toast.java:68)
at android.widget.Toast.makeText(Toast.java:231)
你从工作线程调用它。您需要在主线程中调用Toast.makeText()(以及处理UI的大多数其他函数)。例如,您可以使用处理程序。
在文档中查找与UI线程通信。简而言之:
// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message message) {
// This is where you do your work in the UI thread.
// Your worker tells you in the message what to do.
}
};
void workerThread() {
// And this is how you call it from the worker thread:
Message message = mHandler.obtainMessage(command, parameter);
message.sendToTarget();
}
其他选项:
你可以使用Activity.runOnUiThread()。直截了当,如果你有一个活动:
@WorkerThread
void workerThread() {
myActivity.runOnUiThread(() -> {
// This is where your UI code goes.
}
}
你也可以发布到主循环程序。如果你只有一个Context,这很有用。
@WorkerThread
void workerThread() {
ContextCompat.getMainExecutor(context).execute(() -> {
// This is where your UI code goes.
}
}
弃用:
你可以使用AsyncTask,它对大多数在后台运行的东西都很有效。它有钩子,你可以调用它来指示进度,以及什么时候完成。
它很方便,但如果使用不当,可能会泄漏上下文。它已被正式弃用,您不应该再使用它了。
错误原因:
工作线程是用来做后台任务的,你不能在工作线程的UI上显示任何东西,除非你调用像runOnUiThread这样的方法。如果你试图在UI线程上显示任何东西而不调用runOnUiThread,将会有一个java.lang.RuntimeException。
所以,如果你在一个活动中,但从工作线程调用Toast.makeText(),这样做:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
上面的代码确保您在UI线程中显示Toast消息,因为您是在runOnUiThread方法中调用它。所以不再有java.lang.RuntimeException。
下面是Kotlin使用Coroutine的解决方案:
通过MainScope()使用CoroutineScope扩展类:
class BootstrapActivity : CoroutineScope by MainScope() {}
然后简单地这样做:
launch {
// whatever you want to do in the main thread
}
不要忘记添加协程的依赖项:
org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}