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

开机后后台启动服务连接服务器超时问题排查

问题分析与解决方案

我一眼就看到了核心问题——你在Service的onCreate()里调用了AsyncTask.execute().get()!这个get()方法是同步阻塞调用,它会让当前线程(也就是Service的主线程)一直等待AsyncTask完成后台任务才会继续执行。这不仅会导致Service卡死无法正常初始化,甚至会触发ANR(应用无响应),你的监听逻辑根本没机会正常跑起来。

下面是具体的问题拆解和修复方案:

1. 移除阻塞的get()调用,让AsyncTask真正异步执行

Service的onCreate()运行在主线程,绝对不能在这里做阻塞操作。你需要直接执行AsyncTask,不要用get()等待结果,而是通过onProgressUpdate()或者回调来处理收到的消息。

2. 修复AsyncTask中的监听逻辑bug

你的connectAndListen()方法里有个低级错误:

while ((message = in.readLine()) != null){
    message = in.readLine(); // 这里又读了一次,会跳过第一行数据!
    break;
}

第一次readLine()已经拿到了消息,第二次调用会直接读取下一行(如果有的话),导致你丢失了实际收到的内容。

3. 适配Android版本限制

  • BOOT_COMPLETED广播限制:Android 3.1及以上版本,应用安装后必须被用户手动启动过一次,系统才会发送开机广播给它。如果你的应用从来没被打开过,BootReceiver根本不会触发。
  • 前台服务要求:Android 8.0(API 26)及以上,后台服务会被系统限制,必须启动为前台服务并显示一个低优先级通知,否则Service会被系统杀死。

修正后的代码示例

修正后的AppService

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.widget.Toast;
import androidx.core.app.NotificationCompat;

public class AppService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 适配Android O及以上的前台服务要求
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "app_listener_channel",
                    "后台消息监听",
                    NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this, "app_listener_channel")
                    .setSmallIcon(R.drawable.ic_launcher_foreground) // 替换成你的应用图标
                    .setContentTitle("消息监听服务")
                    .setContentText("正在监听服务器消息")
                    .build();
            startForeground(1, notification);
        }

        Toast.makeText(this, "In service app", Toast.LENGTH_LONG).show();
        // 直接启动AsyncTask,不要调用get()
        new ListenForUpdates(this).execute();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

修正后的ListenForUpdates AsyncTask

import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.lang.ref.WeakReference;

public class ListenForUpdates extends AsyncTask<Void, String, Void> {
    private static final int portNumber = 12302;
    private ServerSocket serverSocket;
    private Socket socket;
    private BufferedReader in;
    private WeakReference<Context> contextRef; // 使用弱引用避免内存泄漏

    public ListenForUpdates(Context context) {
        contextRef = new WeakReference<>(context);
    }

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            serverSocket = new ServerSocket(portNumber);
            // 循环监听,直到任务被取消
            while (!isCancelled()) {
                socket = serverSocket.accept();
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                
                String message;
                // 修复重复readLine()的问题
                while ((message = in.readLine()) != null) {
                    publishProgress(message); // 将消息传递到主线程显示
                    break; // 如果只需要处理一条消息就断开连接,否则移除break持续监听
                }
                
                // 关闭当前连接的资源
                in.close();
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 在主线程处理收到的消息
    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        Context context = contextRef.get();
        if (context != null) {
            Toast.makeText(context, "收到消息:" + values[0], Toast.LENGTH_LONG).show();
        }
    }

    // 任务取消时清理资源
    @Override
    protected void onCancelled() {
        super.onCancelled();
        try {
            if (in != null) in.close();
            if (socket != null) socket.close();
            if (serverSocket != null) serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

额外注意事项

  • 服务器端连接:如果是真机测试,不要用10.0.2.2(这是模拟器指向主机的特殊IP),需要改用你的服务器所在的实际IP,并且确保手机和服务器在同一局域网,防火墙没有拦截12302端口。
  • BootReceiver触发条件:安装应用后,一定要手动打开一次应用,否则开机广播不会被触发。如果应用被用户强制停止,也会收不到开机广播。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:38:03