[英]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: 您有几种解决方案可供选择:
IntentService
instead of Service
. IntentService
而不是Service
。 IntentService
has its own Handler and operates on a separate Thread. IntentService
具有自己的Handler,并在单独的Thread上运行。 AsyncTask
. AsyncTask
。 IMPORTANT : you need to wrap the logic itself, not the Service
-starting logic. Service
逻辑。 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.