报错提示
遇到一个报错: java.lang.RuntimeException: Can't create handler inside thread Thread[OkHttp https://a.fxltsbl.com/...] that has not called Looper.prepare() 分析
1. 这个报错提示是在一个没有调用 Looper.prepare() 的线程中尝试创建一个 Handler 对象。
在 Android 开发中这是不允许的。在 Android 中,Handler 通常用于与 UI 线程进行通信,因此必须在 UI 线程上创建和使用它。
2. 根据报错信息:
java.lang.RuntimeException: Can't create handler inside thread Thread[OkHttp https://a.fxltsbl.com/...] that has not called Looper.prepare()
可以看出问题出现在名为 OkHttp https://a.fxltsbl.com/... 的线程中,这是一个非 UI 线程,但尝试在这个线程上创建了 Handler。
解决方法
解决方法通常是确保 Handler 的创建和使用发生在主线程(UI 线程)上,或者如果需要在后台线程中使用 Handler,则需要先创建一个与该线程关联的 Looper。以下两种解决方法参考:
1. 第一种方法
可以从报错看出:当前在子线程中尝试创建了一个 Handler 实例,而 Android 的 Handler 需要在主线程中使用,因为它依赖于主线程的消息循环(Looper)。
如果在代码中,我们使用的网络请求的回调方法是在 OkHttp 的工作线程中执行的,那么直接在这里创建 Handler 是不合适的。
解决这个问题的方法是,在回调方法中确保使用主线程来执行 callback.onFailure() 和 callback.onResponse() 方法。
Android 中有几种方式可以切换到主线程,最常见的是使用 runOnUiThread() 方法或者使用 Handler 来进行线程间通信。
修改后的代码示例,使用 runOnUiThread() 来确保在主线程执行回调:
private static void setHttpRequestAgent() { //创建okhttpclient对象 OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); //创建Request 对象 Request request = new Request.Builder() .url("https://api.github.com/") .build(); //创建call对象 Call call = okHttpClient.newCall(request); //通过call.enqueue方法来提交异步请求 call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { // 在这里处理异步请求失败的逻辑,切换到主线程执行回调 runOnUiThread(() -> callback.onFailure(e.getMessage())); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { // 在这里处理异步请求成功的逻辑,切换到主线程执行回调 runOnUiThread(() -> { try { callback.onResponse(response.code(), response.body().string()); } catch (IOException e) { callback.onFailure(e.getMessage()); } }); } }); } }); } // 在 Activity 或者 Fragment 中定义一个辅助方法 runOnUiThread,用于确保在主线程执行任务 private void runOnUiThread(Runnable action) { new Handler(Looper.getMainLooper()).post(action); }
在上面的代码中,使用了 runOnUiThread() 方法来确保在主线程上执行 callback.onFailure() 和 callback.onResponse()。这样可以避免在子线程中直接操作 UI 导致的问题。
2. 第二种方法
如果希望在子线程中使用 Handler
,需要先调用 Looper.prepare()
初始化一个 Looper,并且在使用完毕后调用 Looper.loop()
来启动消息循环。
这样可以确保在子线程中正确使用 Handler
来进行消息处理,包括处理网络请求的回调。
修改后的示例代码,以在子线程中使用 Handler
处理网络请求的回调:
private static void setHttpRequestAgent() { OkHttpClient client = new OkHttpClient.Builder().build(); MTSDK.getInstance().setHttpRequestAgent(new HttpRequestAgent() { @Override public void request(String protocol, String url, String params, HttpRequestCallback callback) { new Thread(() -> { // 初始化 Looper Looper.prepare(); Handler handler = new Handler(Looper.myLooper()) { @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); switch (msg.what) { case MSG_FAILURE: callback.onFailure((String) msg.obj); break; case MSG_RESPONSE: ResponseData responseData = (ResponseData) msg.obj; callback.onResponse(responseData.code, responseData.body); break; } } }; RequestBody body = RequestBody.create(params, MediaType.parse("application/json; charset=utf-8")); Request request = new Request.Builder() .url(url) .post(body) .build(); // 使用之前创建的 OkHttpClient 实例 client 进行网络请求 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { // 处理请求失败的逻辑,通过 Handler 发送消息到主线程处理回调 Message message = handler.obtainMessage(MSG_FAILURE, e.getMessage()); message.sendToTarget(); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { // 处理请求成功的逻辑,通过 Handler 发送消息到主线程处理回调 String responseBody = response.body().string(); ResponseData responseData = new ResponseData(response.code(), responseBody); Message message = handler.obtainMessage(MSG_RESPONSE, responseData); message.sendToTarget(); } }); // 启动消息循环 Looper.loop(); }).start(); } }); } // 定义一个简单的数据类用于存储响应信息 private static class ResponseData { int code; String body; ResponseData(int code, String body) { this.code = code; this.body = body; } } // 定义消息类型 private static final int MSG_FAILURE = 1; private static final int MSG_RESPONSE = 2;
上面的代码中,在 request
方法中创建了一个新的线程,并在该线程中初始化了一个 Looper 和 Handler。
在网络请求的回调方法中,通过 Handler 发送消息到主线程处理回调,确保了在子线程中正确使用了 Looper 和 Handler 来进行线程间通信。
这种方法适合于需要在子线程中处理网络请求的情况,并且需要将结果传递回主线程更新 UI。
标签:lang,java,void,callback,Handler,线程,Looper,new,报错 From: https://www.cnblogs.com/yddbkdz/p/18344036