flutter_blue + MethodChannel.invokeMethod + java.lang.NullPointerException

友盟崩溃日志报了这样一个问题,说是扫描蓝牙设备回调时 MethodChannel 为空:

java.lang.NullPointerException: Attempt to invoke virtual method 'void io.flutter.plugin.common.MethodChannel.invokeMethod(java.lang.String, java.lang.Object)' on a null object reference
	at com.pauldemarco.flutter_blue.FlutterBluePlugin$5.run(SourceFile:1)
	at android.app.Activity.runOnUiThread(Activity.java:7152)
	at com.pauldemarco.flutter_blue.FlutterBluePlugin.invokeMethodUIThread(SourceFile:1)
	at com.pauldemarco.flutter_blue.FlutterBluePlugin.access$400(SourceFile:1)
	at com.pauldemarco.flutter_blue.FlutterBluePlugin$2.onScanResult(SourceFile:6)
	at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run(BluetoothLeScanner.java:524)
	at android.os.Handler.handleCallback(Handler.java:938)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loop(Looper.java:236)
	at android.app.ActivityThread.main(ActivityThread.java:7896)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)

理了一遍,发现 flutter_blue 的 MethodChannel 会在 MainActivity 的 onCreate 中初始化,这个时候还没有开启蓝牙扫描,这就奇怪了:
[ com.pauldemarco.flutter_blue.FlutterBluePlugin ]

private void invokeMethodUIThread(final String name, final byte[] byteArray)
    {
        activity.runOnUiThread(
                new Runnable() {
                    @Override
                    public void run() {
                        channel.invokeMethod(name, byteArray);
                    }
                });
    }
    private void setup(
            final BinaryMessenger messenger,
            final Application application,
            final Activity activity,
            final PluginRegistry.Registrar registrar,
            final ActivityPluginBinding activityBinding) {
        synchronized (initializationLock) {
            Log.i(TAG, "setup");
            this.activity = activity;
            this.application = application;
            this.context = application;
            channel = new MethodChannel(messenger, NAMESPACE + "/methods");
            channel.setMethodCallHandler(this);
            stateChannel = new EventChannel(messenger, NAMESPACE + "/state");
            stateChannel.setStreamHandler(stateHandler);
            mBluetoothManager = (BluetoothManager) application.getSystemService(Context.BLUETOOTH_SERVICE);
            mBluetoothAdapter = mBluetoothManager.getAdapter();
            if (registrar != null) {
                // V1 embedding setup for activity listeners.
                registrar.addRequestPermissionsResultListener(this);
            } else {
                // V2 embedding setup for activity listeners.
                activityBinding.addRequestPermissionsResultListener(this);
            }
        }
    }
    @Override
    public void onAttachedToActivity(ActivityPluginBinding binding) {
        activityBinding = binding;
        setup(
                pluginBinding.getBinaryMessenger(),
                (Application) pluginBinding.getApplicationContext(),
                activityBinding.getActivity(),
                null,
                activityBinding);
    }


所以找了一下官网 issues:https://github.com/pauldemarco/flutter_blue/issues/649
按照上面答友的方案试了一下,果然不会了:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';

class MainPage extends StatelessWidget {
  Future<bool> _onWillPop() async {
    // A little workaround for issue https://github.com/pauldemarco/flutter_blue/issues/649
    if (Platform.isAndroid) {
      if (await FlutterBlue.instance.isScanning.first) {
        // Also close any open connections you may have.
        await FlutterBlue.instance.stopScan();
        // not sure if 200 milliseconds is enough on every device. Slower devices may need more time.
        await Future.delayed(Duration(milliseconds: 200));
      }
    }
    return true;
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: _onWillPop,
      child: // Your body goes here
    );
  }
}

通过对事件日志的分析,发现在退出应用后,再马上进来很容易复现这个问题,所以做了以下猜想:

是否有这样的可能:当第一次进入后,MethodChannel 初始化完成调用系统蓝牙扫描,这时退出,再马上进来,蓝牙还在扫描,而这一次 MethodChannel 还没初始化,就报这个错误?

补充

线上观测后,这个问题还是会出现,特别是在华为手机,崩溃率特别高。

原先以为是升级版本带来的问题(0.7.x),那就恢复到旧版本(0.6.x),还是会有问题。

既然官方迟迟没有修复,那就自己改源码:直接修改 flutter_blue 的 Android 模块代码,在 FlutterBluePlugin.java 中发生空指针异常的地方,加上非空判断,why not ~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值