Java Android蓝牙连接工具
我的应用程序可以连接蓝牙设备并读取数据,但当蓝牙离线时,我的应用程序将冻结屏幕,直到找到设备或超时。以下是主要功能: Manifest.xmlJava Android蓝牙连接工具,java,android,multithreading,bluetooth,Java,Android,Multithreading,Bluetooth,我的应用程序可以连接蓝牙设备并读取数据,但当蓝牙离线时,我的应用程序将冻结屏幕,直到找到设备或超时。以下是主要功能: Manifest.xml <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <application
<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>
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();
}
}
}
主要功能:
@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");
}
}
更新:
另一个文件:AbstractGateWayService&将其更改为extends 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();
}
公共抽象类AbstractGatewayService扩展了IntentService{
私有静态最终字符串标记=AbstractGatewayService.class.getName();
私有最终IBinder绑定器=新的AbstractGatewayServiceBinder();
保护上下文ctx;
受保护的布尔值isRunning=false;
线程t=新线程(新的可运行线程(){
@凌驾
公开募捐{
Log.e(标记“线程运行…”);
long futureTime=System.currentTimeMillis()+10000;
而(System.currentTimeMillis()您的问题是调用了startService()中的套接字连接逻辑(正如您正确推断的,这是一个阻塞调用)
方法。Android中的服务
虽然在逻辑上与应用程序的主流程分离,但默认情况下在同一线程上运行。通过在服务中调用阻止调用,可以阻止UI线程
您有多种解决方案可供选择:
- 使用
IntentService
而不是Service
IntentService
有自己的处理程序并在单独的线程上运行
- 将逻辑保留在当前点,但将其包装在
异步任务中重要:您需要包装逻辑本身,而不是服务
启动逻辑
- 完全删除
服务
部分,将逻辑放入异步任务
取决于您的选择,IntentService
解决方案似乎最适合更复杂的应用程序,而创建AsyncTask
将是最快速、最直接的方法:-)Hi@Kelevandos谢谢你的回复,我想我会使用IntentService,我还更新了我的帖子,加入了我的更改并添加了抽象服务类,因为我已经实现了startService()方法,我应该将其移动到onHandleIntent中吗?我想知道我应该将什么放入onHandleIntent方法中。谢谢您可以尝试将所有逻辑移动到其中并检查其是否有效。您的示例中有大量代码,因此如果没有更广泛的上下文,我无法说是否有效:-)此外,对于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();
}