2013-05-27 2 views
2

У меня есть активность, которая отображает значения датчиков и отправляет их в синхронную очередь из метода onSensorChanged. У меня есть тайм-аут в очереди публикации, так что метод onSensorChanged не блокирует, когда очередь блокируется. Затем я ожидаю, что метод будет вызываться при нажатии кнопки «Назад», однако это не так, и экран просто зависает, не возвращаясь к предыдущему экрану. Любая идея, почему это происходит?back button not call onPause

Btw, когда очередь не блокируется (данные удаляются подписчиком), тогда все работает так, как ожидается, вызывается при нажатии кнопки «Назад».

public void onSensorChanged(SensorEvent event) { 
    TextView tvX = (TextView) findViewById(R.id.textViewRemLinAccX); 
    TextView tvY = (TextView) findViewById(R.id.textViewRemLinAccY); 
    TextView tvZ = (TextView) findViewById(R.id.textViewRemLinAccZ); 
    String x = String.format(format, event.values[0]); 
    String y = String.format(format, event.values[1]); 
    String z = String.format(format, event.values[2]); 
    tvX.setText(x); 
    tvY.setText(y); 
    tvZ.setText(z); 

    try { 
     if (btConnection.isRunning()) { 
      Log.i(TAG, "+++ queue values"); 
      queue.offer(constructData(x, y, z), 1, TimeUnit.SECONDS); 
     } 
    } catch (InterruptedException e) { 
     Log.e(TAG, "+++ err " + e.toString()); 
    } 

} 
+0

A/вы блокируете поток пользовательского интерфейса или B/переопределение onBackPressed или onKeyEvent – njzk2

+0

Я не переопределение onBackPressed или onKeyEvent. И я не думаю, что я блокирую поток пользовательского интерфейса. – PerceptualRobotics

ответ

0

Если вы блокируете интерфейс с другими операциями (при выполнении чего-то на основном потоке), а затем кнопку назад не будет работать, вы должны сделать любую операцию, которая занимает много времени в фоновом потоке.

+0

Я не думаю, что я блокирую поток пользовательского интерфейса, поскольку queue.offer истекает время, если сообщение не публикуется в очереди. – PerceptualRobotics

+0

как это реализовано? Единственная причина, по которой кнопка «Назад» не реагирует, связана с тем, что поток пользовательского интерфейса заблокирован. – bogdan

+0

См. OnSensorChanged в исходном вопросе – PerceptualRobotics

0

Это, кажется, разрешено, хотя я не совсем уверен, как я это сделал, поэтому включил код для других. Я сделал много реструктуризации, чтобы убедиться, что ресурсы соединения были очищены должным образом, и теперь методы onPause и onDestroy вызываются при нажатии кнопки «Назад».

Fyi, эта активность открывает соединение Bluetooth и отправляет данные датчика на другой компьютер, который будет использоваться для управления роботом LEGO NXT.

package uk.co.moonsit.apps.sensors.remote; 

import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.SynchronousQueue; 
import java.util.concurrent.TimeUnit; 

import uk.co.moonsit.apps.sensors.R; 
import uk.co.moonsit.bluetooth.BluetoothConnection; 
import android.hardware.Sensor; 
import android.hardware.SensorEvent; 
import android.hardware.SensorEventListener; 
import android.hardware.SensorManager; 
import android.os.Bundle; 
import android.app.Activity; 
import android.content.Context; 
import android.util.Log; 
import android.view.Menu; 
import android.view.WindowManager; 
import android.widget.TextView; 

public class RemoteLinearAccelerationActivity extends Activity implements 
     SensorEventListener { 

    private static final String TAG = "RemoteLinearAccelerationActivity"; 

    private BlockingQueue<String> queue; 
    private SensorManager mSensorManager; 
    private Sensor mLinAcc; 
    private String format = "%.3f"; 
    private String type; 
    private BluetoothConnection btConnection; 
    private String delimiter = "|"; 
    private String cr; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_remote_linear_acceleration); 
     getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 
     byte[] crb = new byte[1]; 
     crb[0] = 13; 
     cr = new String(crb); 
     mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 
     mLinAcc = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); 
     queue = new SynchronousQueue<String>(); 
     type = "LinAcc"; 
     btConnection = new BluetoothConnection(queue, "00001101-0000-1000-8000-00805F9B34FB", "<MAC address here>", "11", "28,13"); 
     Log.i(TAG, "+++ onCreate "); 

    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.remote_linear_acceleration, menu); 
     return true; 
    } 

    @Override 
    public void onAccuracyChanged(Sensor arg0, int arg1) { 
    } 

    @Override 
    public void onSensorChanged(SensorEvent event) { 
     TextView tvX = (TextView) findViewById(R.id.textViewRemLinAccX); 
     TextView tvY = (TextView) findViewById(R.id.textViewRemLinAccY); 
     TextView tvZ = (TextView) findViewById(R.id.textViewRemLinAccZ); 
     String x = String.format(format, event.values[0]); 
     String y = String.format(format, event.values[1]); 
     String z = String.format(format, event.values[2]); 
     tvX.setText(x); 
     tvY.setText(y); 
     tvZ.setText(z); 

     try { 
      String msg = constructData(x, y, z); 
      if (btConnection.isRunning()) { 
       Log.i(TAG, "+++ queue values"); 
       queue.offer(msg, 10, TimeUnit.SECONDS); 
      } 
     } catch (InterruptedException e) { 
      Log.e(TAG, "+++ err " + e.toString()); 
     } 

    } 

    private String constructData(String x, String y, String z) { 
     StringBuilder sb = new StringBuilder(); 
     sb.append(type + delimiter); 
     sb.append(x + delimiter); 
     sb.append(y + delimiter); 
     sb.append(z); 
     sb.append(cr); 
     return sb.toString(); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     Log.i(TAG, "+++ onPause unregisterListener "); 
     mSensorManager.unregisterListener(this); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     Log.i(TAG, "+++ onResume registerListener "); 
     mSensorManager.registerListener(this, mLinAcc, SensorManager.SENSOR_DELAY_NORMAL); 
     Log.i(TAG, "+++ onResume start btConnection"); 
     new Thread(btConnection).start(); 
    } 

    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     Log.i(TAG, "+++ onDestroy closing btConnection"); 
     btConnection.stop(); 
    } 

} 



package uk.co.moonsit.bluetooth; 

import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.IOException; 
import java.util.UUID; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.TimeUnit; 

import uk.co.moonsit.messaging.BeginEndEnvelope; 

import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothSocket; 
//import android.os.ParcelUuid; 
import android.util.Log; 

public class BluetoothConnection implements Runnable { 
    private static final String TAG = "BluetoothConnection"; 

    private final BlockingQueue<String> queue; 
    private BluetoothAdapter mBluetoothAdapter; 
    private BluetoothDevice device; 
    private BluetoothSocket clientSocket; 
    private DataInputStream in = null; 
    private DataOutputStream out = null; 
    private String address; 
    private boolean isConnected = false; 
    private BeginEndEnvelope envelope; 
    private String uuid; 
    private boolean isRunning = true; 

    public BluetoothConnection(BlockingQueue<String> q, String ud, String a, 
      String start, String end) { 
     uuid = ud; 
     queue = q; 
     address = a; 
     mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
     envelope = new BeginEndEnvelope(start, end); 
    } 

    private void getDevice() throws IOException { 
     device = mBluetoothAdapter.getRemoteDevice(address); 
    } 

    private void getSocket() throws IOException { 
     clientSocket = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid)); 
     mBluetoothAdapter.cancelDiscovery(); 
    } 

    private boolean connect() { 

     if (!isConnected) { 
      Log.i(TAG, "+++ connecting"); 
      try { 
       getSocket(); 

       Log.i(TAG, "+++ b4 connect"); 
       clientSocket.connect(); 
       Log.i(TAG, "+++ connected"); 

       isConnected = true; 

       in = new DataInputStream(clientSocket.getInputStream()); 
       out = new DataOutputStream(clientSocket.getOutputStream()); 
       Log.i(TAG, "+++ streams created"); 

      } catch (IOException e) { 
       Long sleep = (long) 10000; 
       Log.e(TAG, "+++ connection failed, sleep for " + sleep); 
       try { 
        Thread.sleep(sleep); 
       } catch (InterruptedException e1) { 
        e1.printStackTrace(); 
       } 
      } 
     } 
     return isConnected; 
    } 

    public void run() { 

     try { 
      getDevice(); 
     } catch (IOException e) { 
      Log.e(TAG, "+++ device error " + e.toString()); 
     } 
     while (isRunning) { 
      try { 
       processData(); 
      } catch (Exception e) { 
       Log.e(TAG, "+++ data error " + e.toString()); 
      } 
     } 
     close(); 
     Log.i(TAG, "+++ ending bluetooth run"); 
    } 

    private void closeSocket() { 
     if (clientSocket != null) 
      try { 
       clientSocket.close(); 
       Log.d(TAG, "+++ socket closed"); 

      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
    } 

    private void closeStreams() { 
     if (in != null) 
      try { 
       in.close(); 
       Log.d(TAG, "+++ input stream closed"); 
      } catch (IOException e) { 
       Log.e(TAG, "+++ input stream not closed " + e.toString()); 
      } 

     if (out != null) 
      try { 
       out.close(); 
       Log.d(TAG, "+++ output stream closed"); 
      } catch (IOException e) { 
       Log.e(TAG, "+++ output stream not closed " + e.toString()); 
      } 
    } 

    private void close() { 
     closeStreams(); 
     closeSocket(); 

     isConnected = false; 
    } 

    public void stop() { 
     isRunning = false; 
    } 

    public boolean isRunning() { 
     return isRunning; 
    } 

    public void setRunning(boolean isRunning) { 
     this.isRunning = isRunning; 
    } 

    private void processData() throws Exception { 

     try { 

      String outData = null; 
      int timer = 0; 
      while (outData == null) { 
       if (!connect()) 
        return; 
       Log.i(TAG, "+++ waiting on queue "); 
       outData = queue.poll(1, TimeUnit.SECONDS);// .take(); 
       if (timer++ > 15) { 
        return; 
       } 
      } 
      envelope.sendMessage(outData, out); 
      String inData = envelope.receiveMessage(in); 
      Log.i(TAG, "+++ response " + inData); 
     } catch (Exception e) { 
      Log.e(TAG, "+++ processData error " + e.toString()); 
      close(); 
      throw e; 
     } 

    } 

} 
+0

Исправление, этот код не разрешил проблему, но я думаю, что я выяснил эту проблему. Что было, что все, что вызывает onSensorChanged, ставит в очередь события. Таким образом, моя очередь замедляла поток пользовательского интерфейса, что означало, что было много вызовов onSensorChanged, чтобы догнать события. Это означало, что поток пользовательского интерфейса падал далеко позади и стал невосприимчивым. Я решил эту проблему, заменив SynchronousQueue на LinkedList, который не ждет на другом конце очереди, и я позволю другому концу (поток, не относящемуся к пользовательскому интерфейсу) справиться с проблемой обработки. – PerceptualRobotics