2016-07-18 6 views
1

マイアプリを実装しますが、Bluetoothがオフラインのときには、デバイスまたはタイムアウトを見つけるまで、私のアプリは、画面がフリーズします。ここでは主な機能は以下のとおりです。AndroidのBluetoothの接続は、データをBlutoothのデバイスと接続して読むことができます

た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

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

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: 別のファイル: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(); 
} 

私は接続ボタンを押すと、アプリがサービスを初期化しますが、それはまた、メインスレッド上でアニメーションをフリーズするを拡張するためにそれを変更私が明示的にそれを別のスレッドに入れるとしても。 logcatに基づいて、私はBluetoothManager.javaファイル内sock.connect()目的球は、コールバックを待っていると思います。すべてがバックグラウンドで実行されるように実装するにはどのように実装する必要がありますか?私もhere

で任意の助けをすべてのコードを入れ

は大歓迎です!ありがとう

答えて

2

問題は、startService()メソッドでSocket接続ロジック(正しく差し引くと、ブロックコール)を呼び出すことです。アンドロイドでServices、論理的にデフォルトで同じThread上で実行する、アプリのメインフローから分離しています。サービス内でブロッキングコールを呼び出すと、UIスレッドがブロックされます。

  • 利用IntentService代わりのService

    あなたがから選択するいくつかのソリューションを持っています。 IntentServiceは独自のハンドラを持ち、別のスレッドで動作します。

  • 現在のポイントでロジックを残すが、AsyncTaskでそれをラップします。 重要:あなたは、ロジック自体、ないService - 出発ロジックをラップする必要があります。 AsyncTaskを作成することが最速になりながら
  • が完全にService一部を削除し、ちょうどそれはあなたが何を選ぶかはあなた次第ですAsyncTask

のロジックを入れ、IntentServiceソリューションは、より複雑なアプリケーションのための最高のようですそして

+0

こんにちは@Kelevandos :-)最もストレートなアプローチお返事のおかげで、私は私がIntentServiceを使用すると思う、私はまた私の変更が含まれるように私のポストを更新し、私はすでに実装されてきたことから、抽象サービスクラスを追加しましたstartService()メソッドをonHandleIntentに移動する必要がありますか?私はonHandleIntentメソッドに何を入れるべきかを知りたい。 – Deidara

+0

ありがとうございました。そこにあるすべてのロジックを動かし、動作するかどうかを調べることができます。あなたの例にはたくさんのコードがありますので、広い文脈がな​​いかどうかはわかりません:-)また、IntentServiceの設定に関しては、カスタムスレッドの代わりにルーパーを使ってハンドラを作成して使うことができます。 – Kelevandos

+1

ありがとうございます。私はこの問題を解決するためにAsyncTaskを使用しました。 – Deidara

関連する問題