音乐播放器通过BLE

时间:2018-06-10 15:34:15

标签: android multithreading bluetooth-lowenergy bluetooth-gatt

我正在构建一个由BLE收到的消息控制的Android音乐播放器。我的应用程序在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;}

        }}}}

音乐播放器:

public int[] bname=new int[]{R.drawable.playinv, R.drawable.pausex, R.drawable.pauseinv, R.drawable.playx,
        R.drawable.nextinv, R.drawable.nextx, R.drawable.previousinv, R.drawable.previousx, R.drawable.vdowninv,
        R.drawable.vdownx, R.drawable.vupinv, R.drawable.vupx};

private Map<UUID, BluetoothGattCharacteristic> map = new HashMap<UUID, BluetoothGattCharacteristic>();

private final ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName,
                                   IBinder service) {

        mBluetoothLeService = ((RBLService.LocalBinder) service)
                .getService();
        if (!mBluetoothLeService.initialize()) {
            Log.e(TAG, "Unable to initialize Bluetooth");
            finish();
        }
        // Automatically connects to the device upon successful start-up
        // initialization.
        final Handler handler =new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mBluetoothLeService.connect(mDeviceAddress);
            }
        },2000);

    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        mBluetoothLeService = null;
    }
};

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();

        if (RBLService.ACTION_GATT_DISCONNECTED.equals(action)) {
        } else if (RBLService.ACTION_GATT_SERVICES_DISCOVERED
                .equals(action)) {
            getGattService(mBluetoothLeService.getSupportedGattService());
        } else if (RBLService.ACTION_DATA_AVAILABLE.equals(action)) {
            displayData(intent.getByteArrayExtra(RBLService.EXTRA_DATA));
        }
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.music_player);
    checkperms();
    vup= findViewById(R.id.vup);
    vdown=findViewById(R.id.vdown);
    next =findViewById(R.id.next);
    previous= findViewById(R.id.previous);
    playpause =findViewById(R.id.plpau);
    info=findViewById(R.id.textView);
    tload=findViewById(R.id.load);
    audioManager=(AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
    Toast.makeText(getApplicationContext(),"Android Version: "+Build.VERSION.SDK_INT, Toast.LENGTH_LONG).show();
   // mediaPlayer = MediaPlayer.create(getApplicationContext(), tracks[current]);

    tload.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            getSongs();
            MUSIC_LOADED=1;
            info.setText(songT[current]);
            Uri trackUri = ContentUris.withAppendedId(
                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,songIDS[current]);
            mediaPlayer=MediaPlayer.create(getApplicationContext(), trackUri);
        }
    });
    playpause.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (pp) {
                mediaPlayer.start();
                playpause.setBackgroundResource(R.drawable.pausex);
                pp = FALSE;
            } else {
                mediaPlayer.pause();
                playpause.setBackgroundResource(R.drawable.playx);
                pp = TRUE;}
        }});

    next.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
           nextTrack();
        } });
    previous.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            previousTrack();
        } });
    vdown.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            volumeDown(audioManager);
        }});
    vup.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            volumeUp(audioManager);            }});

    Intent intent = getIntent();
    mDeviceAddress = intent.getStringExtra(Device.EXTRA_DEVICE_ADDRESS);
    mDeviceName = intent.getStringExtra(Device.EXTRA_DEVICE_NAME);
    //        getActionBar().setTitle(mDeviceName);
    //      getActionBar().setDisplayHomeAsUpEnabled(true);
    Intent gattServiceIntent = new Intent(this, RBLService.class);
    bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onResume() {
    super.onResume();

    registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
    //mediaPlayer.stop();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == android.R.id.home) {
        mBluetoothLeService.disconnect();
        mBluetoothLeService.close();
       // mediaPlayer.stop();
        System.exit(0);
    }

    return super.onOptionsItemSelected(item);
}

@Override
protected void onStop() {
    super.onStop();

    unregisterReceiver(mGattUpdateReceiver);
    //mediaPlayer.stop();

}

@Override
protected void onDestroy() {
    super.onDestroy();

    mBluetoothLeService.disconnect();
    mBluetoothLeService.close();
    //mediaPlayer.stop();
    System.exit(8);
}

private void displayData(byte[] byteArray) {
    if (MUSIC_LOADED==1){
        if (byteArray != null) {
        String data = new String(byteArray);
      x= data.substring (data.length()-1);
        //Toast.makeText(getApplicationContext(),x,Toast.LENGTH_SHORT).show();
        if (x.equals("1")){
            selector=10;
            colorChange(vup,selector);
            Toast.makeText(getApplicationContext(),"Infitex_keypress_001"+"\n"+ "Volume up",Toast.LENGTH_SHORT).show();
            volumeUp(audioManager);
        }
        if (x.equals("3")){
            selector=4;
            colorChange(next,selector);
            Toast.makeText(getApplicationContext(),"Infitex_keypress_003"+"\n"+ "Track Advance",Toast.LENGTH_SHORT).show();
            nextTrack();
        }
        if (x.equals("5") ){
            if (pp){
            selector=0;} else selector= 2;
            colorChange(playpause,selector);
            Toast.makeText(getApplicationContext(),"Infitex_keypress_005"+"\n"+ "Play/Pause",Toast.LENGTH_SHORT).show();
            playPause(playpause);}

     if(x.equals("7")){
         selector=6;
         colorChange(previous,selector);
         Toast.makeText(getApplicationContext(),"Infitex_keypress_007"+"\n"+ "Track Reverse",Toast.LENGTH_SHORT).show();
         previousTrack();
        }
     if(x.equals("9")){
         selector=8;
         colorChange(vdown,selector);
         Toast.makeText(getApplicationContext(),"Infitex_keypress_009"+"\n"+ "Volume Down",Toast.LENGTH_SHORT).show();
         volumeDown(audioManager);
        }
    }}}

private void getGattService(BluetoothGattService gattService) {
    if (gattService == null)
        return;

    BluetoothGattCharacteristic characteristic = gattService
            .getCharacteristic(RBLService.UUID_BLE_SHIELD_TX);
    map.put(characteristic.getUuid(), characteristic);

    BluetoothGattCharacteristic characteristicRx = gattService
            .getCharacteristic(RBLService.UUID_BLE_SHIELD_RX);
    mBluetoothLeService.setCharacteristicNotification(characteristicRx,
            true);
    mBluetoothLeService.readCharacteristic(characteristicRx);
}

private static IntentFilter makeGattUpdateIntentFilter() {
    final IntentFilter intentFilter = new IntentFilter();

    intentFilter.addAction(RBLService.ACTION_GATT_CONNECTED);
    intentFilter.addAction(RBLService.ACTION_GATT_DISCONNECTED);
    intentFilter.addAction(RBLService.ACTION_GATT_SERVICES_DISCOVERED);
    intentFilter.addAction(RBLService.ACTION_DATA_AVAILABLE);
    return intentFilter;
}

void nextTrack(){
    mediaPlayer.pause();
    current+=1;
    if (current==5){
        current=0;
    }

    getURI();
    info.setText(songT[current]);
    playpause.setBackgroundResource(R.drawable.pausex);
    mediaPlayer.start();
    pp=FALSE;

}
void previousTrack(){
    mediaPlayer.pause();
    if (current==0){
        current=4;}
    else {
        current -= 1;
    }
    getURI();

    info.setText(songT[current]);
    playpause.setBackgroundResource(R.drawable.pausex);
    mediaPlayer.start();
    pp=FALSE;
}
public void playPause(ImageButton imageButton){
    if (pp) {
        mediaPlayer.start();
        imageButton.setBackgroundResource(R.drawable.pausex);
        pp = FALSE;
    } else if(pp==FALSE) {
        mediaPlayer.pause();
        imageButton.setBackgroundResource(R.drawable.playx);
        pp = TRUE;
    }

}
public void volumeDown(AudioManager audioManager){
    audioManager.adjustVolume(AudioManager.ADJUST_LOWER,AudioManager.FLAG_PLAY_SOUND);
}
public void volumeUp(AudioManager audioManager){
    audioManager.adjustVolume(AudioManager.ADJUST_RAISE,AudioManager.FLAG_PLAY_SOUND);
}
public void colorChange(final ImageButton imageButton, final int name){
        final int last= name+1;
    new CountDownTimer(1500, 1000) {
        public void onTick(long millisUntilFinished) {
            imageButton.setBackgroundResource(bname[name]);
        }
        public void onFinish() {
            imageButton.setBackgroundResource(bname[last]);
        }
    }.start();
}
    //  public void bCheck(ImageButton imageButton){
    public void getSongs(){
    int i=0;
    ContentResolver contentResolver=getContentResolver();
    Uri uri= EXTERNAL_CONTENT_URI;
    Cursor songcursor= contentResolver.query(uri,null,null,null,null);

    if (songcursor!=null && songcursor.moveToFirst()) {
    int songtitle=songcursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
    int songID=songcursor.getColumnIndex(MediaStore.Audio.Media._ID);

    do{
        songT[i] = songcursor.getString(songtitle);
        songIDS[i]=songcursor.getLong(songID);
        i+=1;
    }
    while(songcursor.moveToNext());
    songcursor.close();

}}
public void getURI(){
    Uri trackUri = ContentUris.withAppendedId(
            android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,songIDS[current]);
    mediaPlayer=MediaPlayer.create(getApplicationContext(), trackUri);
}
private void checkperms(){
    //Toast.makeText(this,"version", Toast.LENGTH_LONG);
    if(Build.VERSION.SDK_INT>19) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
            Toast.makeText(getApplicationContext(), "permissions not granted", Toast.LENGTH_SHORT)
                    .show();
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.READ_EXTERNAL_STORAGE))
                Toast.makeText(getApplicationContext(),"pls grant permissions", Toast.LENGTH_SHORT)
                        .show();
            else {
                // No explanation needed; request the permission
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                        MainActivity.permconst);
                }

        }}}

}

和logcat:

com.example.parlatas.messages I/AndroidRuntime: VM exiting with result code 0, cleanup skipped.

I / WindowManager:WIN DEATH:Window {9297a52 u0 com.example.parlatas.messages / com.example.parlatas.messages.MainActivity} I / ActivityManager:进程com.example.parlatas.messages(pid 8530)已经死亡:前TOP  W / ActivityManager:强制删除ActivityRecord {b15576d u0 com.example.parlatas.messages / .MusicPlayer t245}:app死了,没有保存状态  W / InputDispatcher:channel&#39; d7b3552 com.example.parlatas.messages / com.example.parlatas.messages.MusicPlayer(server)&#39; 〜消费者关闭输入通道或发生错误。事件= 0x9  E / InputDispatcher:channel&#39; d7b3552 com.example.parlatas.messages / com.example.parlatas.messages.MusicPlayer(server)&#39; 〜频道不可挽回地被打破,将被处置!  I / WindowManager:WIN DEATH:Window {d7b3552 u0 com.example.parlatas.messages / com.example.parlatas.messages.MusicPlayer}  W / InputDispatcher:尝试取消注册已经未注册的输入频道&#39; d7b3552 com.example.parlatas.messages / com.example.parlatas.messages.MusicPlayer(server)&#39;  W / NotificationService:对象死于尝试隐藏com.example.parlatas.messages包中的通知android.app.ITransientNotification$Stub$Proxy@c10b00c

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

2 个答案:

答案 0 :(得分:0)

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

classNamePrefix

然后,您必须提供权限,或者应该定位较低的API级别。

答案 1 :(得分:0)

您是否尝试获得运行时权限?

https://developer.android.com/reference/java/lang/Runtime

查看链接。您可以获取运行时权限并解决问题。