You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android中使用Imgur API上传图片时触发android.os.NetworkOnMainThreadException错误求助

这个问题我太熟了!你遇到的android.os.NetworkOnMainThreadException是Android开发里非常常见的坑——你在主线程(也就是UI线程)里直接执行了网络请求,而Android从API 11开始就严格禁止这种操作,因为网络请求是耗时任务,会阻塞主线程导致界面卡顿,甚至触发ANR(应用无响应)。

接下来给你两种靠谱的解决方案,都是让网络请求在后台线程执行:

方案一:用OkHttp的异步请求(推荐,最贴合你当前的代码)

直接把你upload方法里的同步执行改成OkHttp的异步回调,这样网络请求会在后台线程跑,不会阻塞主线程:

public void upload(String encoded){
    OkHttpClient client = new OkHttpClient().newBuilder()
        .build();
    RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
        .addFormDataPart("image",encoded)
        .build();
    Request request = new Request.Builder()
        .url("https://api.imgur.com/3/image")
        .post(body)
        .addHeader("Authorization", "Client-ID {{MY_ID}}")
        .build();
    
    // 用enqueue异步执行请求,代替同步的execute
    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
            // 失败回调:如果要更新UI(比如弹Toast),必须切回主线程
            runOnUiThread(() -> {
                Toast.makeText(getApplicationContext(), "图片上传失败", Toast.LENGTH_SHORT).show();
            });
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()) {
                String responseContent = response.body().string();
                Log.wtf("RESPONSE", responseContent);
                // 成功回调:更新UI同样要切回主线程
                runOnUiThread(() -> {
                    Toast.makeText(getApplicationContext(), "图片上传成功", Toast.LENGTH_SHORT).show();
                    // 这里可以放更新UI的代码,比如设置头像
                    // profilePic.setImageBitmap(captureImage);
                });
            } else {
                Log.wtf("RESPONSE", "上传失败,状态码:" + response.code());
                runOnUiThread(() -> {
                    Toast.makeText(getApplicationContext(), "上传失败,状态码:" + response.code(), Toast.LENGTH_SHORT).show();
                });
            }
            // 记得关闭response,避免资源泄漏
            response.close();
        }
    });
}

方案二:用AsyncTask(适合传统Java写法,不过已被标记为Deprecated)

如果你习惯用AsyncTask,也可以把上传逻辑封装到AsyncTask里,它会自动帮你处理线程切换:

// 定义一个内部AsyncTask类
private class UploadImageTask extends AsyncTask<String, Void, String> {

    // 这个方法在后台线程执行,专门处理耗时任务
    @Override
    protected String doInBackground(String... params) {
        String encodedImage = params[0];
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("image", encodedImage)
                .build();
        Request request = new Request.Builder()
                .url("https://api.imgur.com/3/image")
                .post(body)
                .addHeader("Authorization", "Client-ID {{MY_ID}}")
                .build();
        
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                return response.body().string();
            } else {
                return "上传失败,状态码:" + response.code();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "请求异常:" + e.getMessage();
        }
    }

    // 这个方法在主线程执行,用来处理请求结果、更新UI
    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Log.wtf("RESPONSE", result);
        Toast.makeText(getApplicationContext(), result.contains("成功") ? "上传成功" : "上传失败", Toast.LENGTH_SHORT).show();
    }
}

然后把原来的upload(encoded);替换成:

new UploadImageTask().execute(encoded);

最后补充两个注意点:

  1. 确保你的AndroidManifest.xml里已经添加了网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
  1. 如果你上传后发现Imgur没有正确识别图片,可以试试给Base64字符串加上前缀data:image/png;base64,,也就是把encoded改成"data:image/png;base64," + encoded,有些时候Imgur需要这个前缀来识别图片类型。

内容的提问来源于stack exchange,提问作者Shardul Birje

火山引擎 最新活动