Can‘t create handler inside thread that has not called Looper.prepare() 应用闪退

记录一下bug,卡了半天,最后是gpt给出的方法。

bug

2023-11-02 13:23:44.227 20096-20134 成功                      com.miao.myapplicationdemo04         E  {
                                                                                                    	"code":"200",
                                                                                                    	"data":"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQk33iNdA8Iey7J6XrBsidqn6u8EDLWPHsfEUgLQ3qiTikhPKDTzZkpAfU/O0x6NvSKa7Dp0+uqWT3vnW1De0+3u8mCYdVfOdH94VG4xg5U5UrRJei8HhPiXuvKQ+6NBtebCCW5adZ4pBgOiU14cJLhVmm+dYiLo3IDD5LqrlomQIDAQAB",
                                                                                                    	"msg":"成功"
                                                                                                    }
2023-11-02 13:23:44.374 20096-20134 AndroidRuntime          com.miao.myapplicationdemo04         E  FATAL EXCEPTION: OkHttp Dispatcher
                                                                                                    Process: com.miao.myapplicationdemo04, PID: 20096
                                                                                                    java.lang.RuntimeException: Can't create handler inside thread Thread[OkHttp http://121.40.169.166:8989/...,5,main] that has not called Looper.prepare()
                                                                                                    	at android.os.Handler.<init>(Handler.java:205)
                                                                                                    	at android.os.Handler.<init>(Handler.java:118)
                                                                                                    	at android.view.textservice.SpellCheckerSession$1.<init>(SpellCheckerSession.java:106)
                                                                                                    	at android.view.textservice.SpellCheckerSession.<init>(SpellCheckerSession.java:106)
                                                                                                    	at android.view.textservice.TextServicesManager.newSpellCheckerSession(TextServicesManager.java:181)
                                                                                                    	at android.widget.SpellChecker.resetSession(SpellChecker.java:127)
                                                                                                    	at android.widget.SpellChecker.setLocale(SpellChecker.java:148)
                                                                                                    	at android.widget.SpellChecker.spellCheck(SpellChecker.java:223)
                                                                                                    	at android.widget.Editor.updateSpellCheckSpans(Editor.java:788)
                                                                                                    	at android.widget.Editor.sendOnTextChanged(Editor.java:1359)
                                                                                                    	at android.widget.TextView.sendOnTextChanged(TextView.java:9758)
                                                                                                    	at android.widget.TextView.setText(TextView.java:5733)
                                                                                                    	at android.widget.TextView.setText(TextView.java:5571)
                                                                                                    	at android.widget.EditText.setText(EditText.java:122)
                                                                                                    	at android.widget.TextView.setText(TextView.java:5528)
                                                                                                    	at com.miao.myapplicationdemo04.core.http.OkhttpActivity$3.onResponse(OkhttpActivity.java:79)
                                                                                                    	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
                                                                                                    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
                                                                                                    	at java.lang.Thread.run(Thread.java:764)
2023-11-02 13:23:44.568 20096-20134 Process                 com.miao.myapplicationdemo04         I  Sending signal. PID: 20096 SIG: 9
2023-11-02 13:23:44.727  1954-2047  InputDispatcher         system_server                        E  channel 'b940c49 com.miao.myapplicationdemo04/com.miao.myapplicationdemo04.core.http.OkhttpActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

问题

发送get请求后,数据可以正常显示,但是应用很快闪退。

看一下源码:

public class OkhttpActivity extends AppCompatActivity {
    private String url = "http://121.40.169.166:8989/rsapks";
    private EditText tvRes;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.okhttp_layout);
        tvRes = findViewById(R.id.et_res);
        findViewById(R.id.btn_get).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                get();
            }
        });
        findViewById(R.id.btn_post).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                post();
            }
        });
    }

    /**
     * 异步get请求
     */
    private void get() {
        //第一步获取okHttpClient对象
        OkHttpClient client = new OkHttpClient.Builder()
                .build();
        //第二步构建Request对象
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        //第三步构建Call对象
        Call call = client.newCall(request);
        //第四步:异步get请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
//                Log.i("ttit", e.getMessage());
                Log.i("错误", e.getMessage());
            }

//            @Override
//            public void onResponse(Call call, Response response) throws IOException {
//                //得到的子线程
//                String result = response.body().string();
//                Log.e("成功", result);
//                tvRes.setText(result);
//            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // 得到的子线程
                final String result = response.body().string();
                Log.e("成功", result);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvRes.setText(result);
                    }
                });
            }
        });
    }

其中

总结:

法一:

因为试图在非UI线程中更新UI元素,这是不被允许的,因为Android要求UI操作必须在主线程中执行。在你的代码中,tvRes.setText(result) 尝试在onResponse回调的子线程中执行,导致了闪退。

使用 runOnUiThread 方法,可以像这样修改 onResponse 回调:

@Override
public void onResponse(Call call, Response response) throws IOException {
    // 得到的子线程
    final String result = response.body().string();
    Log.e("成功", result);
    
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            tvRes.setText(result);
        }
    });
}

这将确保 tvRes.setText(result) 在主线程上执行,而不会导致闪退。

法二:

可以使用 Handler 来实现相同的目标。在OkhttpActivity 中,可以声明一个 Handler 对象,然后在 onResponse 中使用它来发送消息来更新UI

private Handler handler = new Handler(Looper.getMainLooper());

@Override
public void onResponse(Call call, Response response) throws IOException {
    // 得到的子线程
    final String result = response.body().string();
    Log.e("成功", result);
    
    handler.post(new Runnable() {
        @Override
        public void run() {
            tvRes.setText(result);
        }
    });
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值