[英]How to detect bluetooth changes (connection state and characteristic) when app is in background without a foreground service
[英]Prevent onDestroy when Bluetooth connection state changes
目標
問題
代碼中沒有任何內容可以偵聽和/或應對藍牙連接狀態的變化做出反應。
問題表現在 BroadcastReceiver 的使用中,而 BroadcastReceiver 又使用意圖啟動 Activity。 出於某種原因,活動在其生命周期中繼續運行,產生新的窗口,即使藍牙連接的唯一變化是BluetoothAdapterProperties: CONNECTION_STATE_CHANGE
我僅在帶有 Android N 的 Nexus 6P 上對此進行了測試。我還不知道這種實現對任何其他設備意味着什么樣的影響。 但我至少需要在一台設備上完成這項工作。
更新
我做了一些實驗,發現如果我不在 AndroidManifest 中注冊 BroadcastReceiver,調用 onDestroy 的問題就會消失。 但是,我希望能夠對藍牙連接設備做出反應,以便我可以啟動我的活動,然后處理輸入。 如果每次新設備連接/斷開時活動都被破壞,這將根本不起作用。 如果 BroadcastReceiver 已經在運行,那么讓 BroadcastReceiver 完成活動的原因是什么,我可以控制這種行為嗎?
更新 2
我還可以得出結論,使用此方法https://stackoverflow.com/a/6529365/975641禁用靜態聲明的 BroadcastReceiver 不會改善情況。 一旦 Manifest-BroadcastReceiver 從 Android 捕獲 ACL_CONNECTED 意圖並啟動我的自定義活動,它就會在連接狀態更改時(通常在 ACL_DISCONNECTED 之前)無情地調用 onDestroy。 我是否在 Manifest 中聲明了 ACL_DISCONNECTED 並不重要。 只要我讓我的接收器監聽 ACL_CONNECTED 意圖並基於此啟動我的 Activity,當連接狀態發生變化時就會調用 onDestroy。 太令人沮喪了。
艙單
<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);
}
}
活動
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();
}
};
}
當我運行此代碼時,我得到以下鏈:
我無法理解為什么此時重新啟動活動會被破壞。 活動已經在運行,BroadcastReceiver 只向已經運行的活動發送廣播。 我無法弄清楚為什么 Activity 有理由殺死自己然后再次重新啟動。 這讓我處於 Activity 仍在運行的狀態,但它不是啟動的原始 Activity。
然而,我確實在 logcats 中看到一些似乎與此有關的東西,它在這個序列中;
06-02 15:45:09.156 26431 26431 D BT:設備斷開連接
06-02 15:45:09.213 19547 19547 D 藍牙適配器服務: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 BluetoothAdapterProperties: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
在 AndroidManifest.xml 中為 Activity 添加以下內容,它對我有用。
android:configChanges="keyboard|keyboardHidden"
閱讀此https://developer.android.com/guide/components/broadcasts.html#effects_on_process_state 后,我可能可以安全地得出結論,調用 onDestroy 的原因是因為接收器影響了它運行的進程,實際上意味着當接收者運行它的 onReceive 方法時,它會銷毀自己並帶走 Activity。
我當然希望它以不同的方式工作,但我相信這就是有效發生的事情,需要采取另一種方法。
我知道這個答案很晚了,但是我的活動標簽遇到了這個問題。 在清單文件中,我為 configChange 添加了以下行。
android:configChanges="keyboard|orientation|screenSize|keyboardHidden|navigation|screenLayout"
現在我的應用程序不會自我毀滅。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.