voz voy paraguas oye necesitar mañana google funciones descargar desactivar asistente ajustes activar android sockets android-fragments bluetooth

android - voy - Zócalos de cierre Bluetooth cuando se usa reconocimiento de voz



ok google voy a necesitar el paraguas mañana (1)

Implementé este tutorial en mi aplicación, pero hice muchos cambios ... He creado un TabLayout así que lo que hice (no creo que sea una buena idea, bueno, no lo es, ya que no funciona :)) en cada fragmento que copia pegué el código del tutorial (creé los enchufes para conectarme a mi Bluetooth , creo conexión al dispositivo ...) y cuando lo probé solo con una Activity funcionó bien ... pero cuando agregué el TabLayout , comenzó a no funcionar. Creo que podría hacer todo el código del Bluetooth en la Activity y luego trabajar con los objetos de esa Activity (del Fragment quiero decir ...) el problema es que en onPause() tengo esto:

@Override public void onPause() { super.onPause(); Toast.makeText(getActivity(), "onPause", Toast.LENGTH_SHORT).show(); try { btSocket.close(); } catch (IOException e2) { } }

Y cada vez que uso esto:

private void startVoiceRecognitionActivity(){ Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.VoiceControllerText)); startActivityForResult(intent, REQUEST_CODE); }

Entra en onPause() y luego el socket está cerrado, y no puedo enviar información a Bluetooth Intenté comentar la línea btSocket.close(); pero el error dice que el socket is closed , no comenté la línea de la otra Tab (solo tengo 2) ¿debería comentar también el socket.close() de la otra Tab ? ....

Estoy buscando una solución que me ayude a implementar / guiar cómo implementar todo el código de Bluetooth como otra clase o algo así, que si ingreso el onPause() desde una Tab el socket no se cierra.

Y, por cierto, no estoy seguro de que copiar pegando el código del Bluetooth (Son lo mismo en un Fragment que el otro ...) es una buena idea ... el mismo UUID mismo ...

Si necesitan más código para verificarlo, háganmelo saber y lo publicaré.

Gracias.

EDITAR

Primero tengo la primera Activity que envié a MainActivity la MAC address siguiente manera:

Intent i = new Intent(DeviceListActivity.this, MainActivity.class); i.putExtra(EXTRA_DEVICE_ADDRESS, address); i.putExtra("name", name); startActivity(i);

Este es el código más importante de mi DeviceListActivity ...

La segunda cosa que tengo es MainActivity pero allí no tengo nada sobre Bluetooth porque hago cosas con Fragments dentro de él ...

Tengo este Fragment que funciona perfecto (es el primero):

Atributos

//Sending info Handler bluetoothIn; private ConnectedThread mConnectedThread; final int handlerState = 0; //used to identify handler message private BluetoothAdapter btAdapter = null; private BluetoothSocket btSocket = null; // SPP UUID service - this should work for most devices private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // String for MAC address private static String address="";

en onCreate() Yo llamo esto:

btAdapter = BluetoothAdapter.getDefaultAdapter();// get Bluetooth adapter if (btAdapter == null) { Toast.makeText(getActivity(), getString(R.string.BtNotSupported), Toast.LENGTH_SHORT).show(); } checkBTState();

Tengo el método para crear el socket

private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException { return device.createRfcommSocketToServiceRecord(BTMODULEUUID); }

Este es mi onResume()

@Override public void onResume() { super.onResume(); //Get MAC del intent Intent intent = getActivity().getIntent(); address = intent.getStringExtra(DeviceListActivity.EXTRA_DEVICE_ADDRESS); //Creates a device with the MAC from DeviceListActivity if(btAdapter!=null) { BluetoothDevice device = btAdapter.getRemoteDevice(address); try { btSocket = createBluetoothSocket(device); } catch (IOException e) { ShowSnack(getString(R.string.SocketCreationFailed), Color.RED); } //Trying to connect try { btSocket.connect(); } catch (IOException e) { try { btSocket.close(); } catch (IOException e2) { } } mConnectedThread = new ConnectedThread(btSocket); mConnectedThread.start(); } else{ ShowSnack(getString(R.string.toast_bt_unavailable), Color.RED); } }

Este es mi onPause()

@Override public void onPause() { super.onPause(); try { //Close socket if leaves the Activity btSocket.close(); } catch (IOException e2) { } }

Y este es el método que llamo para ver si Bluetooth está habilitado o no.

private void checkBTState() { if (btAdapter == null) { ShowSnack(getString(R.string.toast_bt_unavailable), Color.RED); } else { if (btAdapter.isEnabled()) { } else { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, 1); } } }

Esta es mi clase ConnectedThread para enviar y recibir material desde Bluetooth .

private class ConnectedThread extends Thread { private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { InputStream tmpIn = null; OutputStream tmpOut = null; try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer = new byte[256]; int bytes; while (true) { try { bytes = mmInStream.read(buffer); //read bytes from input buffer String readMessage = new String(buffer, 0, bytes); bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget(); } catch (IOException e) { break; } } } //Send stuff to Bluetooth public void write(char input) { try { mmOutStream.write(input); } catch (IOException e) { } } }

Bueno, y ahora, cuando estoy teniendo problemas, está en el segundo Fragment donde tengo el mismo código que aquí ... es por eso que supongo que se bloquea cuando trato de usar Voice recognision ... cuando intento enviar algo a Bluetooth , bueno ... Lo siento si eso es demasiado código pero eso es lo único que espero que entiendas mi problema.


Un problema que enfrenta es que parece que está tratando de administrar el ciclo de vida de su conexión Bluetooth todo desde dentro de su actividad. Como ha visto, esto puede causar problemas cuando las funciones del ciclo de vida de la actividad (como onPause () y onResume ()) no se alinean perfectamente con la duración de la conexión. Para solucionar esto, puede crear un Servicio que maneje todas sus conexiones, envíos y recepciones, y desconectarse de esa conexión Bluetooth. La duración del servicio es independiente de la actividad, por lo que incluso si su usuario está cambiando entre actividades y fragmentos, puede mantener la conexión Bluetooth abierta.

Para configurar su Servicio, cree una nueva clase que amplíe el Servicio y coloque todos sus objetos de manejo de Bluetooth.

public class BluetoothService extends Service { public static final String BLUETOOTH_SERIAL_UUID = "00001101-0000-1000-8000-00805F9B34FB"; private BluetoothSocket mSocket; private String mAddress = "bluetooth_mac_address_here"; public void onCreate() { //Set up Bluetooth socket. BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); if(btAdapter.isEnabled()) { BluetoothDevice btDevice = btAdapter.getRemoteDevice(mAddress); mSocket = btDevice.createRfcommSocketToServiceRecord(BLUETOOTH_SERIAL_UUID); btAdapter.cancelDiscovery(); mSocket.connect(); } } }

Esto configura el objeto mSocket cuando se inicia el servicio por primera vez. Después de ese punto, podrá interactuar con el dispositivo remoto bluetooth mediante simples llamadas a mSocket.getInputStream() y mSocket.getOutputStream() y leer / escribir datos usando esos. Sin embargo, si no está familiarizado con el uso de los Servicios, puede ser un poco confuso cómo transferir sus datos de la Actividad hacia y desde el Servicio. Aquí hay una manera de hacerlo usando Intents.

Dentro de la misma clase BluetoothService, anule onStartCommand() :

public class BluetoothService extends Service { ... public static final String ACTION_SEND_DATA = "send_data"; public static final String ACTION_RECEIVED_DATA = "received_data"; public static final String EXTRA_BLUETOOTH_DATA = "bluetooth_data"; public int onStartCommand(Intent intent, int flags, int startId) { //Register a BroadcastReceiver to handle "send" requests. LocalBroadcastManager.getInstance(this).registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //Parse your data to send from the intent. if(intent.getAction().equals(ACTION_SEND_DATA)) { byte[] data = intent.getByteArrayExtra(EXTRA_BLUETOOTH_DATA); //Send the data over the Bluetooth Socket. try { mSocket.getOutputStream().write(data); } catch(IOException ioe) { //This might happen if you try to write to a closed connection. ioe.printStackTrace(); } } } return Service.START_STICKY; } }

Esto le dará una forma de usar las Intenciones para enviar sus datos desde una Actividad al Servicio, pero aún no recibir esos datos. Voy a llegar a eso más tarde. Tenga en cuenta que he usado LocalBroadcastReceiver para registrar el intento. Esto significa que al BroadcastReceiver que registramos solo se le darán intenciones que se transmitieron desde su aplicación y tienen una acción coincidente. Acabo de usar eso para simplificar las interacciones de intención, pero en el futuro si desea permitir que las aplicaciones externas envíen datos usando su servicio (probablemente poco probable), entonces tendrá que cambiar eso. De todos modos, desde su Actividad, haga lo siguiente para enviar los datos a través de su Servicio:

public class MyActivity extends Activity { public void onCreate(Bundle savedInstanceState) { ... String myString = "This is some data I want to send!"; //Create an intent with action saying to send data //with the byte[] of data you want to send as an extra. Intent sendIntent = new Intent(BluetoothService.ACTION_SEND_DATA); sendIntent.putExtra(BluetoothService.EXTRA_BLUETOOTH_DATA, myString.getBytes()); //Sends the intent to any BroadcastReceivers that have registered receivers for its action. LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } }

Lamentablemente, tengo clase en unos minutos y no puedo terminar esta publicación en este momento, pero estaré lista en unas horas para explicar cómo configurar la parte de recepción. Mientras tanto, no dudes en consultar este código de un proyecto mío que resuelve exactamente estos problemas. Mire la clase TransferManager y cómo utiliza Threads para proporcionar una forma no bloqueante de recibir datos del InputStream del BluetoothSocket.

=============================================== ========================

Bien, ahora veamos cómo puedes usar tu Servicio para recibir datos de tu dispositivo remoto con Bluetooth. Una cosa que debes saber sobre los Servicios es que no se ejecutan en subprocesos separados de tus Actividades. Si bien mantienen su estado y las funciones del ciclo de vida están desacopladas de las de Actividades, todavía se ejecutan en el hilo de la interfaz de usuario principal. Esto significa que si coloca código en su Servicio que es lento o está bloqueando, ralentizará o congelará la IU de su Actividad. Este es un comportamiento que definitivamente queremos evitar, por lo que cuando consideramos recibir datos de un dispositivo Bluetooth (una operación de bloqueo), necesitamos manejar esa operación creando un nuevo subproceso dentro de la clase de servicio personalizada. Definamos una clase personalizada que amplíe Thread como una clase interna de nuestro BluetoothService:

public class BluetoothService extends Service { ... public void onCreate() {...} public int onStartCommand(...) {...} public static class ReceiveThread extends Thread { private boolean isRunning; private InputStream mBluetoothInputStream; public ReceiveThread(InputStream bluetoothInputStream) { mBluetoothInputStream = bluetoothInputStream; isRunning = true; } @Override public void run() { BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(mBluetoothInputStream)); String line; while(isRunning) { try { //This is the line that blocks until a newline is read in. line = bufferedReader.readLine(); } catch(IOException ioe) { //This happens if the InputStream is closed. ioe.printStackTrace(); //Stop the thread from looping. isRunning = false; } //Make sure our line in isn''t null or blank. if(line == null || line.equals("") { continue; //Start again at top of while loop. } //Notify your Activity about the new data. Intent receivedIntent = new Intent(BluetoothService.this, MyActivity.class); receivedIntent.setAction(ACTION_RECEIVED_DATA); receivedIntent.putExtra(EXTRA_BLUETOOTH_DATA); LocalBroadcastManager.getInstance(BluetoothService.this).sendBroadcast(receivedIntent); try { //This is an arbitrary sleep time just to prevent //this from looping without any restriction. Thread.sleep(20); } catch(InterruptedException e) { //This happens if the Thread is interrupted for any reason. e.printStackTrace(); isRunning = false; } } } } }

Bien, ahora puedes girar un nuevo ReceiveThread arrojando unas pocas líneas al final de onStartCommand() en el Servicio:

ReceiveThread receiver = new ReceiveThread(mSocket.getInputStream()); receiver.start();

El último paso es realmente obtener esos datos en su actividad. Para hacer eso, creará un BroadcastReceiver que escuchará las transmisiones enviadas por ReceiveThread. En tu clase de Actividad, pon esto al final de onCreate() :

public void onCreate() { ... LocalBroadcastManager.getInstance(this).registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //Get your data out of the intent. byte[] data = intent.getByteArrayExtra(BluetoothService.EXTRA_BLUETOOTH_DATA); } }, new IntentFilter(BluetoothService.ACTION_RECEIVED_DATA)); }

Se onReceive() método onReceive() cada vez que ReceiveThread de su BluetoothService lee una nueva línea de su dispositivo remoto bluetooth. Dependiendo de su aplicación real, esto puede o no ser adecuado para usted (por ejemplo, si su programa no está basado en texto / comando y no tiene caracteres de nueva línea). Puede cambiar ese comportamiento cambiando el BufferedReader en el ReceiveThread con otro tipo de Reader.

EDITAR:

En tu fragmento has creado un método stub llamado write que pareces estar obsesionado con tener. Tener un método como este requeriría que lo ejecutes como una llamada directa desde la Actividad, que no es lo que deseas. Si miran hacia arriba en esta publicación, verán que he escrito un código que debía llamar desde su Actividad, que usa intenciones para entregar sus datos al Servicio. Mire el fragmento que comienza con public class MyActivity extends Activity . El objetivo de usar intents es que Android Framework se encargará de llevar los datos "adicionales" al Servicio, que luego se desempaqueta en el método onStartCommand() en onStartCommand() en el Servicio, donde se puede ver que OutputStream es siendo escrito a.

La única otra cosa es que olvidé el servicio de return Service.START_STICKY para el método onStartCommand() del Servicio. En cualquier lugar que desee poner ese método de write que hizo en su fragmento, coloque el código sobre la creación y el envío de la intención usando LocalBroadcastManager.