简体   繁体   English

Android蓝牙连接工具

[英]Android Bluetooth Connection Implement

My app can connect with a blutooth device and read data, but when the bluetooth is offline, my app will freeze the screen until it finds the device or timeout. 我的应用程序可以与蓝牙设备连接并读取数据,但是当蓝牙处于离线状态时,我的应用程序将冻结屏幕,直到找到该设备或超时。 Here are the main functions: 主要功能如下:

Manifest.xml 的Manifest.xml

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

    <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>

        <service
            android:name=".MyGatewayService"
            android:enabled="true"
            android:exported="true"></service>
    </application>

</manifest>

BluetoothManager.java BluetoothManager.java

public class BluetoothManager {

        private static final String TAG = BluetoothManager.class.getName();
        private static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

        public static BluetoothSocket connect(BluetoothDevice dev) throws IOException{

            BluetoothSocket sock = null;
            BluetoothSocket socketFallback = null;
            Log.d(TAG,"Start Bluetooth Connection...");
            try
            {
                sock = dev.createRfcommSocketToServiceRecord(myUUID);
                Log.d(TAG, "Probably gonna wait here...");
                sock.connect();
            }catch (Exception e1){
                Log.e(TAG, "There was an error while establishing Bluetooth connection, Failing back...", e1);

            }
            return sock;
        }

    }

MyGateWayService.java MyGateWayService.java

public class MyGatewayService extends AbstractGatewayService{
    private static final String TAG = MyGatewayService.class.getName();
    private BluetoothDevice dev = null;
    private BluetoothSocket sock = null;

@Override
protected void onHandleIntent(Intent intent) {
      //what should I put in here?
}

    @Override
    public void startService() throws IOException {
        final String remoteDevice = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE).getString(Constants.SHARED_PREFERENCES_BLUETOOTH_SELECTION_ADDRESS_KEY, "");

        if (remoteDevice == null||"".equals(remoteDevice)){
            Toast.makeText(getApplicationContext(),"No Bluetooth device selected...",Toast.LENGTH_SHORT).show();
            Log.e(TAG,"No Bluetooth device selected...");
            stopService();
            throw new IOException();
        }else{
            final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
            dev = btAdapter.getRemoteDevice(remoteDevice);
            Log.d(TAG,"Stop bluetooth discovery...");
            btAdapter.cancelDiscovery();
            Log.d(TAG,"Start Service..");
            try{
                startServiceConnection();
            }catch (Exception e){
                Log.e(TAG, "There was an error while establishing connection..." + e.getMessage());



           stopService();
            throw new IOException();
        }
    }
}

    private void startServiceConnection() throws IOException, InterruptedException {
        Log.d(TAG, "Start the connection");
        isRunning = true;

        try{
            sock = com.ibm.us.wuxiaosh.androidbluetoothdemo.BluetoothManager.connect(dev);
        }catch (Exception e2){
            Log.e(TAG, "There was an error while connecting... stop...");
            stopService();
            throw new IOException();
        }


    }

    @Override
    protected void executeQueue(){
        Log.d(TAG,"Executing...");
        while(!Thread.currentThread().isInterrupted()){
            //Log.d(TAG,"Executing ....................");
        }
    }
    @Override
    public void stopService() {
        isRunning = false;

        if (sock!=null){
            try{
                sock.close();
            }catch (IOException e){
                Log.e(TAG, e.getMessage());
            }
            stopSelf();
        }
    }
}

Mainfunction: 主功能:

@Override
        public void onServiceConnected(ComponentName className, IBinder binder) {
            Log.d(TAG, className.toString() + " service is bound");
            isServiceBound = true;
            service = ((AbstractGatewayService.AbstractGatewayServiceBinder) binder).getService();
            service.setContext(MainActivity.this);
            Log.d(TAG, "Starting live data");

            try{
                service.startService();

                Log.d(TAG , "Connected");


            } catch (IOException ioe){
                Log.e(TAG, "Failure Starting Live Data");
                doUnbindService();
            }

        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
        @Override
        public void onServiceDisconnected(ComponentName className) {
            Log.d(TAG, " service is unbound");
            isServiceBound = false;
        }
    };




    private void doBindService(){
        if(!isServiceBound){
            Log.d(TAG, "Binding OBD Service..");

            Log.e(TAG,"start intent 1");
            Intent serviceIntent = new Intent(this, MyGatewayService.class);
            Log.e(TAG,"intent finished");
            bindService(serviceIntent,serviceConn, Context.BIND_AUTO_CREATE);
            Log.e(TAG,"bindService");
        }
    }

    private void doUnbindService(){
        if(isServiceBound){
            if (service.isRunning()){
                service.stopService();

                Log.d(TAG,"Ready");
            }
            Log.e(TAG, "Unbinding OBD Service...");
            unbindService(serviceConn);
            isServiceBound = false;
            Log.e(TAG, "Disconnected");
        }
    }

UPDATE : another file: AbstractGateWayService & changed it to extends intentService 更新 :另一个文件:AbstractGateWayService并将其更改为扩展了intentService

public abstract class AbstractGatewayService extends IntentService{
    private static final String TAG = AbstractGatewayService.class.getName();
    private final IBinder binder = new AbstractGatewayServiceBinder();
    protected Context ctx;
    protected boolean isRunning = false;

    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            Log.e(TAG, "Thread Run...");
                long futureTime = System.currentTimeMillis()+10000;
                while(System.currentTimeMillis()<futureTime) {
                    executeQueue();
                }
        }
    });

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Creating Service...");
        t.start();
        Log.d(TAG, "Service Creating...");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"Destroying service");
        t.interrupt();
        Log.d(TAG,"Service Destroyed");
    }

    class AbstractGatewayServiceBinder extends Binder {
        public AbstractGatewayService getService(){
            return AbstractGatewayService.this;
        }
    }
    public boolean isRunning() {
        return isRunning;
    }

    public void setContext(Context c) {
        ctx = c;
    }

    abstract protected void executeQueue();

    abstract public void startService() throws IOException;

    abstract public void stopService();
}

When I press the connect button, the app will initialize the service but it will also freeze the animation on the main thread, even if I explicitly put it in a separate thread. 当我按下连接按钮时,该应用程序将初始化服务,但即使我将动画显式放置在单独的线程中,它也将冻结主线程上的动画。 Based on the logcat I think the sock.connect() funtion in the BluetoothManager.java file is waiting for the callback. 基于logcat,我认为BluetoothManager.java文件中的sock.connect()函数正在等待回调。 How should I implement to make sure everything runs in the background? 我应如何实施以确保一切都在后台运行?

I also put all the code in here 我也把所有代码都放在这里

Any help are welcome! 欢迎任何帮助! Thanks 谢谢

Your problem is that you invoke the Socket connection logic (which, as you correctly deducted, is a blocking call) in the startService() method. 您的问题是您在startService()方法中调用了Socket连接逻辑(正确地推断是阻塞调用)。 Services in Android, while logically separate from the main flow of the app, run on the same Thread by default. Android上的Services在逻辑上与应用程序的主流程分开,但默认情况下在同一Thread上运行。 By calling a blocking call in the service, you block the UI Thread. 通过在服务中调用阻止调用,可以阻止UI线程。

You have several solutions to choose from: 您有几种解决方案可供选择:

  • Use IntentService instead of Service . 使用IntentService而不是Service IntentService has its own Handler and operates on a separate Thread. IntentService具有自己的Handler,并在单独的Thread上运行。
  • Leave the logic in the current point, but wrap it in an AsyncTask . 将逻辑保留在当前点,但将其包装在AsyncTask IMPORTANT : you need to wrap the logic itself, not the Service -starting logic. 重要信息 :您需要包装逻辑本身,而不是Service逻辑。
  • Drop the Service part altogether and just put the logic in an AsyncTask 完全删除Service部分,然后将逻辑放在AsyncTask

It is up to you what you choose, the IntentService solution seems best for a more complex app, while creating an AsyncTask would be the quickest and most straight-forward approach :-) 取决于您的选择, IntentService解决方案似乎最适合更复杂的应用程序,而创建AsyncTask将是最快,最直接的方法:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM