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

Android Studio Java实现锁屏解锁后自动后台Socket连接并推送通知问题

问题修复方案

现有代码核心问题

  • 广播接收器没有注册ACTION_USER_PRESENT动作,无法接收手机解锁的系统广播
  • 错误将UserPresentBroadcastReceiver同时注册为广播和服务,存在类冲突
  • 在广播的onReceive方法中执行死循环、网络请求等耗时操作,会直接触发ANR(应用无响应),被系统强制杀死进程
  • 网络请求直接运行在主线程,会抛出主线程网络异常
  • Android 12及以上版本PendingIntent未指定可变性flag,会抛出异常

修复步骤

1. 修正AndroidManifest.xml配置

删掉错误的服务注册,新增解锁广播监听、前台服务权限,调整后的完整代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.notification">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <!-- Android 8.0+前台服务所需权限 -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Notification">
        <receiver 
            android:name=".UserPresentBroadcastReceiver"
            android:exported="true">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
                <!--HTC设备开机广播兼容-->
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
                <!--新增解锁广播监听动作-->
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>

        <!--新增独立的消息检查服务-->
        <service
            android:name=".MessageCheckService"
            android:exported="false"/>

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"  />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

2. 简化广播接收器逻辑

广播仅负责触发服务启动,不执行任何耗时操作:

public class UserPresentBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(Intent.ACTION_USER_PRESENT.equals(action) || Intent.ACTION_BOOT_COMPLETED.equals(action)){
            Intent serviceIntent = new Intent(context, MessageCheckService.class);
            // Android 8.0+需要用startForegroundService启动前台服务
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                context.startForegroundService(serviceIntent);
            } else {
                context.startService(serviceIntent);
            }
        } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
            // 关机时停止服务
            context.stopService(new Intent(context, MessageCheckService.class));
        }
    }
}

3. 新增消息检查前台服务

将Socket请求、循环检查、通知逻辑都放到服务的子线程执行:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class MessageCheckService extends Service {
    private Thread checkThread;
    private volatile boolean isRunning = false;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        isRunning = true;

        // Android 8.0+前台服务必须展示运行通知
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    "SERVICE_RUN_CHANNEL",
                    "后台运行通知",
                    NotificationManager.IMPORTANCE_LOW
            );
            getSystemService(NotificationManager.class).createNotificationChannel(serviceChannel);
            Notification runNotification = new NotificationCompat.Builder(this, "SERVICE_RUN_CHANNEL")
                    .setContentTitle("消息检查服务运行中")
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .build();
            startForeground(1, runNotification);
        }

        // 子线程执行循环检查逻辑
        checkThread = new Thread(() -> {
            while (isRunning) {
                Socket client = null;
                PrintWriter printWriter = null;
                BufferedReader bufferedReader = null;
                String newMessage = null;
                try {
                    client = new Socket("192.168.1.13", 1580);
                    printWriter = new PrintWriter(client.getOutputStream(), true);
                    printWriter.write("<meet>/notification/");
                    printWriter.flush();

                    bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                    newMessage = bufferedReader.readLine();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    // 资源释放
                    try {
                        if (client != null) client.close();
                        if (printWriter != null) printWriter.close();
                        if (bufferedReader != null) bufferedReader.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                // 收到有效消息再推送通知
                if (newMessage != null && !newMessage.trim().isEmpty()) {
                    pushNotification(newMessage);
                }

                // 间隔5秒检查
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        });
        checkThread.start();
    }

    private void pushNotification(String content) {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        String msgChannelId = "MSG_NOTIFY_CHANNEL";
        // 适配Android 8.0+通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel msgChannel = new NotificationChannel(
                    msgChannelId,
                    "新消息通知",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            msgChannel.setDescription("收到新消息时推送通知");
            notificationManager.createNotificationChannel(msgChannel);
        }

        // 适配Android 12+ PendingIntent可变性要求
        int pendingFlag = PendingIntent.FLAG_UPDATE_CURRENT;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            pendingFlag |= PendingIntent.FLAG_IMMUTABLE;
        }
        PendingIntent clickIntent = PendingIntent.getActivity(
                this,
                0,
                new Intent(this, MainActivity.class),
                pendingFlag
        );

        Notification notification = new NotificationCompat.Builder(this, msgChannelId)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("新消息")
                .setContentText(content)
                .setAutoCancel(true)
                .setContentIntent(clickIntent)
                .build();
        // 用时间戳作为通知id避免覆盖历史通知
        notificationManager.notify((int) System.currentTimeMillis(), notification);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        isRunning = false;
        if (checkThread != null) {
            checkThread.interrupt();
        }
        stopForeground(true);
    }
}

注意事项

  • 应用首次安装后必须手动打开一次,否则Android系统的安全机制会禁止静态广播触发
  • 国内厂商ROM普遍有后台省电策略,需要手动给应用开启自启动权限、加入后台运行白名单,否则进程被杀死后无法接收广播
  • 如果不需要每5秒循环检查,仅需要每次解锁时检查一次,可以去掉服务内的while循环,检查完成后直接调用stopSelf()停止服务即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 04:06:01