目标:构建一个片段页面,用于发现范围内蓝牙设备的名称和地址,并将其显示在ListView中,用户可以从中选择要连接的设备。它类似于本地设备中的蓝牙扫描过程。
遇到的问题:
有时,扫描过程会持续很长时间(> 5分钟)和 不停止
有时,发现过程很快,并且能够输出“未找到设备”或相应找到的设备的输出名称和地址
有时,虽然在本地蓝牙设置中发现了蓝牙设备,但ListView中的蓝牙设备不会出现在ListView中。但是,当我切换到本地蓝牙设置并切换回我的应用程序时,ListView会开始显示本地蓝牙设置中列出的蓝牙设备。
我花了几周时间试图解决这些问题,但无济于事。欣赏任何可以指出我的错误的灵魂?
图片:
My app's Listview got updated after switching back from Local Bluetooth setting
这是我的代码:
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.content.Intent;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Set;
/**
* A simple {@link Fragment} subclass.
*/
public class Server_fragment extends Fragment {
// Component fields
Switch bluetoothSwitch;
TextView titlePairedDevices;
ListView pairedListView;
TextView titleNewDevices;
ListView newDevicesListView;
ProgressBar progressBar;
// Member fields
private BluetoothAdapter mBluetoothAdapter = null;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter;
private static final int REQUEST_ENABLE_BT = 3;
Set<BluetoothDevice> pairedDevices;
public Server_fragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View v = inflater.inflate(R.layout.fragment_server_fragment, container, false);
// Initialize the switch to perform Bluetooth on/off
bluetoothSwitch = (Switch) v.findViewById(R.id.bluetoothSwitch);
titlePairedDevices = (TextView) v.findViewById(R.id.title_paired_devices);
pairedListView = (ListView) v.findViewById(R.id.paired_devices);
titleNewDevices = (TextView) v.findViewById(R.id.title_new_devices);
newDevicesListView = (ListView) v.findViewById(R.id.new_devices);
progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
// Initialize array adapters.
// One for already paired devices and
// one for newly discovered devices
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(getActivity(), R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter<String>(getActivity(), R.layout.device_name);
// Find and set up the ListView for paired devices
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
// Find and set up the ListView for newly discovered devices
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
IntentFilter filter = new IntentFilter();
// Register for broadcasts when a device is discovered
filter.addAction(BluetoothDevice.ACTION_FOUND);
getActivity().registerReceiver(mReceiver, filter);
// Register for broadcasts when discovery has finished
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
getActivity().registerReceiver(mReceiver, filter);
// Get local Bluetooth Adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
/**
* If the switch is off initially,
* This method enables Bluetooth when user presses switch
* If the switch is on initially,
* This method disables Bluetooth when user presses switch
*/
bluetoothSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
bluetoothSupportCheck();
titlePairedDevices.setVisibility(View.VISIBLE);
displayPairedList();
titleNewDevices.setVisibility(View.VISIBLE);
doDiscovery();
} else {
bluetoothSupportCheck();
titlePairedDevices.setVisibility(View.GONE);
displayPairedList();
titleNewDevices.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
newDevicesListView.setVisibility(View.GONE);
}
}
});
pairedDevices = mBluetoothAdapter.getBondedDevices();
// Set switch mode according to local Bluetooth status
if (mBluetoothAdapter.isEnabled()) {
bluetoothSwitch.setChecked(true);
titlePairedDevices.setVisibility(View.VISIBLE);
displayPairedList();
titleNewDevices.setVisibility(View.VISIBLE);
doDiscovery();
makeDiscoverable();
} else {
bluetoothSwitch.setChecked(false);
titlePairedDevices.setVisibility(View.GONE);
titleNewDevices.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
newDevicesListView.setVisibility(View.GONE);
}
return v;
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onDestroy() {
super.onDestroy();
// Make sure we're not doing discovery anymore
if (mBluetoothAdapter != null) {
mBluetoothAdapter.cancelDiscovery();
}
// Unregister broadcast listeners
getActivity().unregisterReceiver(mReceiver);
}
/**
* This method checks whether Bluetooth is supported
* If yes, ask user for permission to allow Bluetooth to be on
*/
private void bluetoothSupportCheck() {
if (mBluetoothAdapter == null) {
Toast.makeText(getContext(), "No bluetooth device available", Toast.LENGTH_LONG).show();
bluetoothSwitch.setChecked(false);
} else if (!mBluetoothAdapter.isEnabled() && bluetoothSwitch.isChecked()) {
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, REQUEST_ENABLE_BT);
} else {
mBluetoothAdapter.disable();
Toast.makeText(getContext(), "ADAPTER DISABLED", Toast.LENGTH_LONG).show();
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_ENABLE_BT:
if (resultCode == Activity.RESULT_OK) {
makeDiscoverable();
} else {
Toast.makeText(getActivity(), "Bluetooth was not enabled. Exiting...", Toast.LENGTH_SHORT).show();
bluetoothSwitch.setChecked(false);
getActivity().finish();
}
default:
break;
}
}
private void makeDiscoverable() {
if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
/**
* Display the list of paired devices
*/
private void displayPairedList() {
// If there are paired devices, add each one to the ArrayAdapter
// Display the list of paired Bluetooth devices
if (pairedDevices.size() > 0) {
getView().findViewById(R.id.paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
mPairedDevicesArrayAdapter.clear();
if ( bluetoothSwitch.isChecked() ) {
String noDevices = "\t No device has been paired".toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
else {
mPairedDevicesArrayAdapter.clear();
}
}
}
/**
* The on-click listener for all devices in the ListViews
*/
private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
// Cancel discovery because it's costly and we're about to connect
mBluetoothAdapter.cancelDiscovery();
// Get the device MAC address, which is the last 17 chars in the View
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// Finish this Activity
getActivity().finish();
}
};
/**
* The BroadcastReceiver that listens for discovered devices and
* changes the title when discovery is finished
*/
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// When discovery is finished
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
progressBar.setVisibility(View.GONE);
titleNewDevices.setText("Other Available Devices");
// If no new devices found
if (mNewDevicesArrayAdapter.getCount() == 0) {
if ( bluetoothSwitch.isChecked() ) {
String noDevices = "\t No device found".toString();
mNewDevicesArrayAdapter.add(noDevices);
} else {
mNewDevicesArrayAdapter.clear();
}
} else {
if (!bluetoothSwitch.isChecked()) {
mNewDevicesArrayAdapter.clear();
}
}
}
}
};
private void doDiscovery() {
titleNewDevices.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.VISIBLE);
titleNewDevices.setText("Scanning for devices...");
// If we're already discovering, stop it
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
mBluetoothAdapter.startDiscovery();
}
}