蓝牙连接状态更改时防止onDestroy [英] Prevent onDestroy when Bluetooth connection state changes

查看:105
本文介绍了蓝牙连接状态更改时防止onDestroy的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标

  • 如果已连接的蓝牙设备断开连接,并且活动"已在运行,请关闭活动"

问题

  • 当蓝牙设备的连接状态通过 BluetoothAdapterProperties:CONNECTION_STATE_CHANGE 更改时,似乎正在创建一个新的Activity或当前的Activity重新启动.
  • When the bluetooth device connection state changes through BluetoothAdapterProperties: CONNECTION_STATE_CHANGE, it seems like a new Activity is created or the current one restarts.

代码中没有任何内容可以侦听和/或应对蓝牙连接状态的变化做出反应.

There is nothing in the code that listens and/or should react to bluetooth connection state changes.

该问题通过使用BroadcastReceivers表现出来,而后者又使用意图启动了Activity.由于某种原因,即使蓝牙连接的唯一变化是 BluetoothAdapterProperties:CONNECTION_STATE_CHANGE

The problem manifests itself in the use of BroadcastReceivers which in turn starts the Activity using intents. For some reason the Activity keep running through its lifecycle, spawning up new windows, even if the only change in bluetooth connectivity is BluetoothAdapterProperties: CONNECTION_STATE_CHANGE

我仅在带有Android N的Nexus 6P上进行了测试.我还不知道此实现对任何其他设备的意义是什么.但是我至少需要让它在 one 设备上工作.

I've tested this solely on a Nexus 6P with Android N. I have no idea yet what kind of implications this implementation means for any other devices yet. But I at least need to get this working on one device.

更新

我做了一些实验,发现如果我没有在AndroidManifest中注册BroadcastReceiver,则调用onDestroy的问题就消失了.但是,我希望能够对蓝牙连接设备做出反应,以便我可以启动活动然后处理输入.如果每次连接/断开新设备时活动被销毁,则根本无法使用.如果BroadcastReceiver已经在运行,并且可以控制该行为,请问该如何完成该活动的原因是什么?

I have done a fair bit of experimentation and found that if I don't register the BroadcastReceiver in AndroidManifest, the problem with onDestroy being called disappears. But, I want to be able to react to Bluetooth connecting devices, so that I can launch my activity and then process input. If the activity gets destroyed every time a new device connects/disconnects, this won't work at all. What's the reasoning for having the BroadcastReceiver finishing an activity if it's already running and can I control that behaviour?

更新2

我还可以得出结论,使用此方法禁用静态声明的BroadcastReceiver https://stackoverflow.com/a/6529365/975641 不能改善情况.一旦Manifest-BroadcastReceiver从Android捕获到ACL_CONNECTED意图并开始我的自定义活动,当连接状态更改时(通常就在ACL_DISCONNECTED之前),它将无情地调用onDestroy.是否在清单中声明了ACL_DISCONNECTED都没有关系.只要我的接收方正在侦听ACL_CONNECTED意图,并以此为基础启动我的Activity,就可以在连接状态更改时调用onDestroy.真令人沮丧.

I can also conclude that disabling the statically declared BroadcastReceiver using this method https://stackoverflow.com/a/6529365/975641 doesn't improve things. As soon as the Manifest-BroadcastReceiver catches the ACL_CONNECTED intent from Android, and start my custom activity, it will ruthlessly call onDestroy on it when the connection state changes (which is usually just before an ACL_DISCONNECTED). It does not matter if I have ACL_DISCONNECTED declared in the Manifest or not. As long as I have my receiver listening for ACL_CONNECTED intents and I launch my Activity based on that, onDestroy will be called when the connection state changes. So frustrating.

清单

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.VIBRATE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".BtActivity"
        android:launchMode="singleTop" />
    <receiver android:name=".BtConnectionBroadcastReceiver" android:priority="100000">
        <intent-filter>
            <action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
            <action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
            <action android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
            <action android:name="android.intent.action.MEDIA_BUTTON" />
            <action android:name="android.media.VOLUME_CHANGED_ACTION" />
        </intent-filter>
    </receiver>
</application>

BtConnectionBroadcastReceiver

public class BtConnectionBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "BT";
    public static final String BROADCAST_ACTION_CONNECTED = "CONNECTED";
    public static final String BROADCAST_ACTION_DISCONNECTED = "DISCONNECTED";
    SharedPreferences mSharedPreferences;

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        // When discovery finds a device
        if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
            // Get the BluetoothDevice object from the Intent
            Log.d(TAG, "DEVICE CONNECTED");
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            Log.d("DEVICE NAME", device.getName());
            Log.d("DEVICE ADDRESS", device.getAddress());
            Intent i = new Intent(context, BtActivity.class);
            i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
            context.startActivity(i);
        } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
            Log.d(TAG, "DEVICE DISCONNECTED");
            intent = new Intent();
            intent.setAction(BtConnectionBroadcastReceiver.BROADCAST_ACTION_DISCONNECTED);
            context.sendBroadcast(intent);
        }
    }

BtActivity

public class BtActivity extends AppCompatActivity {
private static final String TAG = "BT";
Window mWindow;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_bt);

    Log.d(TAG, "onCreate");
    IntentFilter filter = new IntentFilter(BtConnectionBroadcastReceiver.INTENT_FILTER);
    filter.addAction(BtConnectionBroadcastReceiver.BROADCAST_ACTION_CONNECTED);
    filter.addAction(BtConnectionBroadcastReceiver.BROADCAST_ACTION_DISCONNECTED);
    //registerReceiver(mReceiver, filter);

    mWindow = getWindow();
    WindowManager.LayoutParams params = new WindowManager.LayoutParams();
    //params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF;
    params.screenBrightness = 0.2f;
    mWindow.setAttributes(params);
    mWindow.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
    mWindow.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
    mWindow.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
    mWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
    mWindow.getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                    View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                    View.SYSTEM_UI_FLAG_FULLSCREEN |
                    View.SYSTEM_UI_FLAG_IMMERSIVE);
    }

@Override
protected void onResume() {
    super.onResume();
    Log.d(TAG, "onResume");
}

@Override
protected void onDestroy() {
    super.onDestroy();
    Log.d(TAG, "onDestroy");
}

BroadcastReceiver mReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "BROADCAST RECEIVED IN ACTIVITY");
        String mac;
        if(intent.getAction().equals(BtConnectionBroadcastReceiver.BROADCAST_DEVICE_CONNECTED)) {
            Log.d(TAG, "CONNECT BROADCAST RECEIVED");
            mac = intent.getStringExtra("mac");
            checkConnectedDevice(mac, true); // This adds a device to an internal list
            Log.d(TAG, "Activity nr of devices:" +mNrOfDevices);
        }
        if(intent.getAction().equals(BtConnectionBroadcastReceiver.BROADCAST_DEVICE_DISCONNECTED)) {
            Log.d(TAG, "DISCONNECT BROADCAST RECEIVED");
            mac = intent.getStringExtra("mac");
            checkConnectedDevice(mac, false); // This removes a device from an internal list
            Log.d(TAG, "Activity nr of devices:" +mNrOfDevices);
            if(mNrOfDevices < 1) {
                Log.d(TAG, "No more connected devices");
                finish();
            }
        }
        abortBroadcast();
    }
};
}

运行此代码时,得到以下链接:

When I run this code, I get the following chain:

  1. 启动MainActivity(不包含在内,它仅包含具有默认主布局的活动,以便注册应用程序接收者)
  2. 打开蓝牙设备(之前已经配对过,因此android知道了)
  3. 请等待直到连接并得到以下信息:
    • 已连接设备
    • onCreate
    • onResume
  1. Start MainActivity (not included, it only contains an activity with the default main layout, so that the applications receiver is registered)
  2. Switch on a bluetooth device (This has been paired earlier, so android knows about it)
  3. Wait until it connects and get this:
    • DEVICE CONNECTED
    • onCreate
    • onResume
  • 设备已断开连接
  • onDestroy
  • onCreate
  • onResume

我不明白为什么活动在此刻被破坏而重新开始.该活动已在运行,BroadcastReceiver仅向已运行的活动发送广播.我无法弄清楚为什么Activity有理由杀死自己并然后重新启动.这使我处于活动"仍在运行的状态,但是不是最初启动的活动".

I can't grasp why the activity is getting destroyed restarting at this point. The activity is already running, the BroadcastReceiver only sends a broadcast to an already running activity. I can't figure out why there's a reason for the Activity to kill itself and then restart again. This leaves me in a state of the Activity still running, but it is not the original Activity that was started.

但是,我确实在日志猫中看到了一些与此有关的东西,并且是在此排序中;

I do however see something in the logcats that seem to have something to do with this, and it's in this sequencing;

06-02 15:45:09.156 26431 26431 D BT:设备已断开

06-02 15:45:09.213 19547 19547 D BluetoothAdapterService:handleMessage()-MESSAGE_PROFILE_CONNECTION_STATE_CHANGED

06-02 15:45:09.213 26431 26431 D BT:onDestroy

06-02 15:45:09.214 19547 19547 D BluetoothAdapter属性:CONNECTION_STATE_CHANGE:FF:FF:20:00:C1:47:2-> 0

06-02 15:45:09.216 3502 3805 D CachedBluetoothDevice:onProfileStateChanged:profile HID newProfileState 0

06-02 15:45:09.237 414 414 W SurfaceFlinger:无法记录到二进制事件日志:溢出.

06-02 15:45:09.239 26431 26431 D BT:onCreate

06-02 15:45:09.243 26431 26431 D BT:onResume

推荐答案

已阅读此

Having read this https://developer.android.com/guide/components/broadcasts.html#effects_on_process_state I can probably safely conclude that the reason for why onDestroy gets called is because the receiver affects the process in which it is run, effectively meaning when the receiver has run its onReceive method, it will destroy itself and take the Activity with it.

我当然希望它能以不同的方式工作,但是我相信这是有效的过程,需要采取另一种方法.

I would of course have wished it was working differently, but I believe this is what effectively is going on and need to take another approach.

这篇关于蓝牙连接状态更改时防止onDestroy的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆