Android 通过BLE播放音乐

Android 通过BLE播放音乐,android,multithreading,bluetooth-lowenergy,bluetooth-gatt,Android,Multithreading,Bluetooth Lowenergy,Bluetooth Gatt,我正在构建一个Android音乐播放器,它由通过BLE接收的消息控制。我的应用程序在API 4.4(18)上运行良好,但在8.1(27)中崩溃,可能是因为线程处理不好。这是我的扫描活动和音乐播放器活动,以及来自LogCat的错误 扫描活动 public class MainActivity extends Activity { private BluetoothAdapter mBluetoothAdapter; private static final int REQUEST_ENABLE_B

我正在构建一个Android音乐播放器,它由通过BLE接收的消息控制。我的应用程序在API 4.4(18)上运行良好,但在8.1(27)中崩溃,可能是因为线程处理不好。这是我的扫描活动和音乐播放器活动,以及来自LogCat的错误

扫描活动

public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter;
private static final int REQUEST_ENABLE_BT = 1;
private static final long SCAN_PERIOD = 3000;
private Dialog mDialog;
public static final int permconst=7;
public static List<BluetoothDevice> mDevices = new ArrayList<BluetoothDevice>();
public static MainActivity instance = null;
private View mPermissionRationale;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
    setContentView(R.layout.main);
    checkperms();

    if (!getPackageManager().hasSystemFeature(
            PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, "Ble not supported", Toast.LENGTH_SHORT)
                .show();
        finish();
    }

    final BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        Toast.makeText(this, "Ble not supported", Toast.LENGTH_SHORT)
                .show();
        finish();
        return;
    }

    if (!mBluetoothAdapter.isEnabled()) {
        Intent enableBtIntent = new Intent(
                BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }

    ImageButton btn = (ImageButton) findViewById(R.id.btn);
    btn.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            scanLeDevice();

            showRoundProcessDialog(MainActivity.this, R.layout.loading_process_dialog_anim);

            Timer mTimer = new Timer();
            mTimer.schedule(new TimerTask() {

                @Override
                public void run() {
                    Intent deviceListIntent = new Intent(getApplicationContext(),
                            Device.class);
                    startActivity(deviceListIntent);
                    mDialog.dismiss();
                }
            }, SCAN_PERIOD);
        }
    });

    //scanLeDevice();

    showRoundProcessDialog(MainActivity.this, R.layout.loading_process_dialog_anim);

    Timer mTimer = new Timer();
    mTimer.schedule(new TimerTask() {

        @Override
        public void run() {
            Intent deviceListIntent = new Intent(getApplicationContext(),
                    Device.class);
            startActivity(deviceListIntent);
            mDialog.dismiss();
        }
    }, SCAN_PERIOD);

    instance = this;
}

public void showRoundProcessDialog(Context mContext, int layout) {
    DialogInterface.OnKeyListener keyListener = new DialogInterface.OnKeyListener() {
        @Override
        public boolean onKey(DialogInterface dialog, int keyCode,
                             KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_HOME
                    || keyCode == KeyEvent.KEYCODE_SEARCH) {
                return true;
            }
            return false;
        }
    };

    mDialog = new AlertDialog.Builder(mContext).create();
    mDialog.setOnKeyListener(keyListener);
    mDialog.show();
    // 娉ㄦ��姝ゅ��瑕���惧��show涔���� ������浼���ュ��甯�
    mDialog.setContentView(layout);
}


private void scanLeDevice() {
    //checkperms();
   // new Thread() {
    final Handler handler =new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
           // if(Build.VERSION.SDK_INT>21){

           // mBluetoothAdapter.getBluetoothLeScanner().startScan(mleScanCallback);}    
            mBluetoothAdapter.startLeScan(mLeScanCallback);
                        }
    },4000);
    mBluetoothAdapter.stopLeScan(mLeScanCallback);
}

private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

    @Override
    public void onLeScan(final BluetoothDevice device, final int rssi,
                         byte[] scanRecord) {
        runOnUiThread(new Runnable() {
       // new Thread(){
            @Override
            public void run() {
                if (device != null) {

                    if (mDevices.indexOf(device) == -1)
                        mDevices.add(device);
                }
            }
        });
    }
};

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // User chose not to enable Bluetooth.
    if (requestCode == REQUEST_ENABLE_BT
            && resultCode == Activity.RESULT_CANCELED) {
        finish();
        return;
    }
    super.onActivityResult(requestCode, resultCode, data);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    //scanLeDevice(false);
    mDevices.clear();

    System.exit(0);
}

private void checkperms(){
    if(Build.VERSION.SDK_INT>19) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            Toast.makeText(this, "permissions not granted", Toast.LENGTH_SHORT)
                    .show();
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION))
                Toast.makeText(this, "pls grant permissions", Toast.LENGTH_SHORT)
                        .show();
            else {
                // No explanation needed; request the permission
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},

                        permconst);
                return;}

        }}}}
I/WindowManager:WIN DEATH:Window{9297a52 u0 com.example.parlatas.messages/com.example.parlatas.messages.MainActivity} I/ActivityManager:Process com.example.parlatas.messages(pid 8530)已失效:fore TOP W/ActivityManager:Force removing ActivityRecord{b15576d u0 com.example.parlatas.messages/.MusicLayer t245}:应用程序已死亡,无保存状态 W/InputDispatcher:通道'd7b3552 com.example.parlatas.messages/com.example.parlatas.messages.MusicLayer(服务器)'~使用者关闭输入通道或发生错误。事件=0x9 E/InputDispatcher:通道'd7b3552 com.example.parlatas.messages/com.example.parlatas.messages.MusicLayer(服务器)'~通道已不可恢复地断开,将被释放! I/WindowManager:WIN DEATH:Window{d7b3552 u0 com.example.parlatas.messages/com.example.parlatas.messages.MusicPlayer} W/InputDispatcher:尝试注销已注销的输入通道'd7b3552 com.example.parlatas.messages/com.example.parlatas.messages.MusicPlayer(服务器)' W/NotificationService:对象在试图隐藏通知android.app.ITransientNotification$Stub时死亡$Proxy@c10b00c在包com.example.parlatas.messages中


我有单独的类,其中包含BLE常量和由扫描活动(主活动)填充的蓝牙设备列表。

如果目标API级别高于22,请尝试在清单中添加以下权限。新版本需要粗略位置权限(访问蜂窝位置信息)如果要使用蓝牙硬件。这没有意义,但在新的API级别中需要它

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-feature android:name="android.hardware.bluetooth_le"


您是否尝试获取运行时权限


请看链接。您可以休假运行时权限并解决问题。

所有权限都存在于清单中,并已在应用程序中签入,但谢谢!
com.example.parlatas.messages I/AndroidRuntime: VM exiting with result code 0, cleanup skipped.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-feature android:name="android.hardware.bluetooth_le"