Android开机启动前台服务失败,BroadcastReceiver触发空指针异常
问题根源
你代码里存在两个直接触发报错的核心错误:
- 你直接通过
new location()创建Service实例,Android四大组件(Activity、Service、BroadcastReceiver、ContentProvider)必须由系统调度创建,自行new出来的实例没有绑定系统上下文,调用startForeground时会触发空指针 - 创建PendingIntent时传入了空的
emptyIntent,系统找不到目标Activity类名,这就是报错日志中class name is null的直接触发原因
修复步骤
1. 修改BroadcastReceiver代码
不要自行创建Activity和Service实例,通过系统API启动服务
public class client extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { Intent serviceIntent = new Intent(context, location.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); } } } }
2. 修改Service代码
将前台服务初始化逻辑移到系统回调的onStartCommand中,修正PendingIntent配置
public class location extends Service implements LocationListener { public static double lon, lat; @Override public int onStartCommand(Intent intent, int flags, int startId) { // 创建通知渠道 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { NotificationChannel serviceChannel = new NotificationChannel( "locationService", "位置上报服务", NotificationManager.IMPORTANCE_DEFAULT ); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(serviceChannel); } // PendingIntent指向实际的主页面Activity,不要传空Intent Intent contentIntent = new Intent(this, MapsActivity.class); int pendingFlag = PendingIntent.FLAG_IMMUTABLE; if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) { pendingFlag = 0; } PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, contentIntent, pendingFlag ); Notification notification = new NotificationCompat.Builder(this, "locationService") .setSmallIcon(R.drawable.common_google_signin_btn_icon_dark) .setContentTitle("位置上报中") .setContentIntent(pendingIntent) .build(); // 启动前台服务 startForeground(1, notification); // 补充位置监听的初始化逻辑 LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); try { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 10, this); } catch (SecurityException e) { e.printStackTrace(); } return START_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onLocationChanged(Location location) { if (location != null) { lat = location.getLatitude(); lon = location.getLongitude(); // 这里补充向服务端上报位置的逻辑 } } }
3. 补充AndroidManifest.xml配置
必须添加对应的权限和组件声明,否则无法接收开机广播、启动服务
<!-- 开机广播权限 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- 安卓12及以上位置前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> <!-- 位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 安卓10及以上后台位置权限 --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <application ...> <!-- 注册开机广播Receiver --> <receiver android:name=".client" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <!-- 注册位置服务 --> <service android:name=".location" android:foregroundServiceType="location" android:exported="false" /> </application>
4. 额外注意事项
- 安卓6.0及以上需要在应用内主动弹窗申请位置权限,用户授权后服务才能正常获取位置
- 安卓10及以上需要用户额外授权后台位置权限
- 必须保证用户至少主动打开过一次应用,否则安卓系统会限制应用接收开机广播
- 国内定制ROM普遍有自启动权限限制,需要手动给应用开启自启动权限才能正常收到开机广播启动服务
内容的提问来源于stack exchange,提问作者m mardis
相关产品推荐
相关产品推荐

