Flutter插件无法启动Android Intent服务,空指针异常求助
Flutter Android插件启动前台服务空指针问题修复
问题描述
开发连接手表的Flutter插件时,通过MethodChannel调用Android原生SDK实现后台数据同步,需要启动前台服务,但出现以下空指针错误:
E/MethodChannel#releep_watch_connect: Failed to handle method call java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.Activity io.flutter.embedding.android.FlutterActivity.getActivity()' on a null object reference at com.achatsocial.releep_watch_connect.ReleepWatchConnectPlugin.onMethodCall(ReleepWatchConnectPlugin.java:130) at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233) at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:84) at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:865) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:335) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:8051) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:620) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1011)
同时onAttachedToActivity方法未正确触发,导致activity对象为空,无法启动Intent。
核心问题分析
- 初始化时机错误:
onAttachedToEngine中提前调用activity.getSystemService(),但此时onAttachedToActivity还未执行,activity变量未赋值,直接触发空指针。 - Service启动逻辑冗余:代码中调用
activity.getActivity(),但activity本身就是FlutterActivity实例,无需额外调用;且启动Service可使用ApplicationContext,不需要依赖Activity。 - Activity生命周期未处理:
ActivityAware的部分回调未维护activity状态,可能导致内存泄漏或状态不一致。
修复步骤及代码修改
1. 调整Activity变量与生命周期管理
将FlutterActivity类型改为通用的Activity,并完善所有ActivityAware回调:
public class ReleepWatchConnectPlugin implements FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler, ActivityAware { private Activity activity; private Context appContext; // 保存ApplicationContext,脱离对Activity的依赖 private MethodChannel channel; private EventChannel stream_chanel; private NotificationManager notificationManager; // ... 其他变量定义 @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { appContext = flutterPluginBinding.getApplicationContext(); YCBTClient.initClient(appContext, true); YCBTClient.registerBleStateChange(bleConnectResponse); YCBTClient.deviceToApp(toAppDataResponse); channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "releep_watch_connect"); channel.setMethodCallHandler(this); stream_chanel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "scan_releep_watch"); stream_chanel.setStreamHandler(this); } @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); notificationManager = (NotificationManager) activity.getSystemService(Context.NOTIFICATION_SERVICE); boolean backBoolean = PermissionUtils.checkPermissionArray(activity, permissionArray, 3); } @Override public void onDetachedFromActivityForConfigChanges() { this.activity = null; } @Override public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { activity = binding.getActivity(); } @Override public void onDetachedFromActivity() { this.activity = null; } // ... 其他方法 }
2. 修正Service启动逻辑
使用ApplicationContext启动Service,并适配Android 8.0+的前台服务要求:
@Override public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { if (call.method.equals("syncHeartRate")) { Intent intent = new Intent(appContext, MyBleService.class); intent.putExtra("text", "Hello"); // 适配Android 8.0+启动前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { appContext.startForegroundService(intent); } else { appContext.startService(intent); } // 绑定服务前先判断Activity是否存在 if (activity != null) { activity.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); } else { result.error("ACTIVITY_NULL", "Activity未绑定", null); } } }
3. 实现前台服务的通知要求
在MyBleService中创建前台通知(Android 8.0+需先创建通知渠道):
public class MyBleService extends Service { private static final String CHANNEL_ID = "BLE_SYNC_CHANNEL"; private static final int NOTIFICATION_ID = 1001; @Override public void onCreate() { super.onCreate(); createNotificationChannel(); Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("手表数据同步") .setContentText("正在后台同步心率数据") .setSmallIcon(R.drawable.ic_notification) .build(); startForeground(NOTIFICATION_ID, notification); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "BLE同步服务", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } } // ... 其他服务逻辑 }
额外注意事项
- 确保插件使用新版Flutter嵌入API注册,
ActivityAware的回调才会被正确触发;旧版Activity注册方式需升级。 - 权限申请必须在Activity绑定后执行,避免因
activity为空导致权限请求失败。
内容的提问来源于stack exchange,提问作者Thananat Rueangchot
相关产品推荐
相关产品推荐

