You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android执行不同HTTP请求时出现卡顿问题求助

解决Android中蓝牙回调内发起HTTP请求卡顿的问题

从你提供的代码片段来看,卡顿的核心原因大概率是在主线程中执行了网络操作,或是HTTP请求的实现方式存在线程管理、资源复用的问题。咱们一步步拆解问题并给出优化方案:

问题分析

  • 主线程阻塞风险:onCharacteristicChanged是蓝牙Gatt的回调方法,默认运行在**主线程(UI线程)**中。如果在这里直接发起网络请求,哪怕是用已废弃的AsyncTask,一旦网络请求耗时较长,就会阻塞主线程,导致UI卡顿甚至ANR(应用无响应)。
  • 资源未复用:每次特征更新都创建新的HTTP请求实例,没有复用连接池,会导致频繁的TCP握手/断开,增加额外耗时和系统资源消耗。
  • URL拼接不规范:直接用字符串拼接URL,容易出现格式错误,可读性差且不利于维护。

具体优化方案

1. 把网络请求移到后台线程,用现代异步方案替代AsyncTask

AsyncTask已被官方废弃,推荐用ExecutorService+OkHttp(Java)或Coroutines+OkHttp(Kotlin)来处理异步网络操作,这两种方案都能高效管理后台线程,且OkHttp自带连接池,能大幅提升请求效率。

Java示例(ExecutorService+OkHttp)

首先在build.gradle中引入OkHttp依赖:

implementation 'com.squareup.okhttp3:okhttp:4.12.0'

然后重构你的回调代码:

// 提前初始化线程池和OkHttpClient,避免重复创建资源
private ExecutorService mNetworkExecutor = Executors.newFixedThreadPool(3);
private OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .build();

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    super.onCharacteristicChanged(gatt, characteristic);
    // 将耗时操作抛给后台线程执行
    mNetworkExecutor.execute(() -> {
        try {
            String rawData = new String(characteristic.getValue());
            String[] data = rawData.split("/");
            // 先做数据格式校验,避免数组越界
            if (data.length < 3) {
                Log.e("HTTP_ERROR", "Invalid data format: " + rawData);
                return;
            }
            // 用OkHttp的HttpUrl构建URL,更安全规范
            HttpUrl url = new HttpUrl.Builder()
                    .scheme("http")
                    .host("192.168.1.100")
                    .port(8000)
                    .addPathSegments("rest/store")
                    .addPathSegment(gatt.getDevice().getAddress())
                    .addPathSegment(data[0])
                    .addPathSegment(data[1])
                    .addPathSegment(data[2])
                    .addPathSegment(String.valueOf(System.currentTimeMillis()))
                    .build();

            Request request = new Request.Builder()
                    .url(url)
                    .build();

            // 执行请求并自动关闭响应流
            try (Response response = mOkHttpClient.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    Log.e("HTTP_ERROR", "Request failed, code: " + response.code());
                } else {
                    // 请求成功后的处理逻辑
                    String responseContent = response.body().string();
                    Log.d("HTTP_SUCCESS", "Response content: " + responseContent);
                }
            }
        } catch (Exception e) {
            Log.e("HTTP_ERROR", "Request exception occurred", e);
        }
    });
}

Kotlin示例(Coroutines+OkHttp)

如果是Kotlin项目,用协程会更简洁:

// 声明协程作用域,绑定IO线程池
private val networkScope = CoroutineScope(Dispatchers.IO + SupervisorJob())

override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?) {
    super.onCharacteristicChanged(gatt, characteristic)
    characteristic ?: return
    gatt ?: return
    
    networkScope.launch {
        try {
            val rawData = String(characteristic.value)
            val data = rawData.split("/")
            if (data.size < 3) {
                Log.e("HTTP_ERROR", "Invalid data format: $rawData")
                return@launch
            }
            // 用字符串模板拼接URL,Kotlin中更简洁安全
            val url = "http://192.168.1.100:8000/rest/store/${gatt.device.address}/${data[0]}/${data[1]}/${data[2]}/${System.currentTimeMillis()}"
            
            val client = OkHttpClient()
            val request = Request.Builder().url(url).build()
            // use函数自动关闭响应流
            client.newCall(request).execute().use { response ->
                if (!response.isSuccessful) throw IOException("Unexpected response code: ${response.code}")
                val responseContent = response.body?.string()
                Log.d("HTTP_SUCCESS", "Response content: $responseContent")
            }
        } catch (e: Exception) {
            Log.e("HTTP_ERROR", "Request failed", e)
        }
    }
}

2. 增加请求防抖/合并(针对特征更新频繁的场景)

如果蓝牙特征更新非常频繁(比如每秒多次),频繁发起HTTP请求不仅会导致客户端卡顿,还会给服务器带来压力。可以做以下优化:

  • 设置短延迟(比如500ms),如果延迟内有新的特征数据,就替换旧数据,只发起最后一次请求。
  • 批量收集数据,达到一定数量或时间阈值后再一次性发送。

3. 避免内存泄漏

  • 若使用ExecutorService,在Activity/Fragment销毁时要关闭线程池:mNetworkExecutor.shutdown()。
  • 若使用CoroutineScope,在组件销毁时要取消协程:networkScope.cancel()。
  • 避免持有Activity的强引用,必要时使用WeakReference。

额外注意事项

  • 确保在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
  • 若为Android 9及以上版本,需允许明文HTTP请求(或改用HTTPS),在application标签中添加:
android:usesCleartextTraffic="true"

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:53:20