これはSOでの最初の質問です。私はAndroidプログラミングの初心者です(そして興奮しています)。ここに私の問題があります:Androidフォンとマイクロコントローラーを使用してプロジェクトを構築しています。マイクロコントローラーには距離センサーがあり、その値を送信します。マイクロコントローラに接続して正しい信号を送信することはできましたが、距離測定などを取得できません。アプリケーションがクラッシュしたり、マイクロコントローラーからデータを取得できなかったりすることはありません (私のコンピューターはマイクロコントローラーからデータを取得します (データは文字列です))。Android アプリからの私のコードは次のとおりです。
public class Accelerometer extends Activity {
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int RECIEVE_MESSAGE = 3;
// Program variables
private byte microcOut;
private boolean ledStat;
private boolean connectStat = false;
private Button btnled;
private Button connect_button;
private TextView yAccel, xAccel, incoming;
protected static final int MOVE_TIME = 80;
private long lastWrite = 0;
OnClickListener myClickListener;
ProgressDialog myProgressDialog;
private Toast failToast;
private Handler mHandler,h;
private StringBuilder sb = new StringBuilder();
// Sensor object used to handle accelerometer
private SensorManager mySensorManager;
private List<Sensor> sensors;
private Sensor accSensor;
// Bluetooth Stuff
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
private InputStream inStream = null;
private ConnectThread mConnectThread = null;
private ConnectedThread mConnectedThread;
private String deviceAddress = null;
// Well known SPP UUID (will *probably* map to RFCOMM channel 1 (default) if not in use);
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//Sound Clip to make app prettier
MediaPlayer myclip;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_accelerometer);
myclip = MediaPlayer.create(this, R.raw.cartcar);
myclip.start();
// Finds buttons in .xml layout file
btnled = (Button) findViewById(R.id.led_button1);
connect_button = (Button) findViewById(R.id.connect_button1);
yAccel = (TextView) findViewById(R.id.accText1);
xAccel = (TextView) findViewById(R.id.accText2);
incoming = (TextView) findViewById(R.id.incoming);
// Set Sensor
mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
sensors = mySensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if(sensors.size() > 0) accSensor = sensors.get(0);
myProgressDialog = new ProgressDialog(this);
failToast = Toast.makeText(this, R.string.failedToConnect, Toast.LENGTH_SHORT);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (myProgressDialog.isShowing()) {
myProgressDialog.dismiss();
}
// Check if bluetooth connection was made to selected device
if (msg.what == 1) {
// Set button to display current status
connectStat = true;
connect_button.setText(R.string.connected);
// Reset the BluCar
microcOut = 0;
ledStat = false;
write(microcOut);
}else {
// Connection failed
failToast.show();
}
}
};
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
incoming.setText("Data from Arduino: " + sbprint); // update TextView
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
// Check whether bluetooth adapter exists
btAdapter = BluetoothAdapter.getDefaultAdapter();
if (btAdapter == null) {
Toast.makeText(this, R.string.no_bt_device, Toast.LENGTH_LONG).show();
finish();
return;
}
// If BT is not on, request that it be enabled.
if (!btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
/**********************************************************************
* Buttons for controlling BluCar
*/
connect_button.setOnClickListener(new View.OnClickListener() {
// Connect to Bluetooth Module
@Override
public void onClick(View v) {
if (connectStat) {
// Attempt to disconnect from the device
disconnect();
}else{
// Attempt to connect to the device
connect();
}
}
});
// Toggle Headlights
btnled.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ledStat) {
microcOut = (byte) (microcOut & 124);
btnled.setText(R.string.ledbuttonON);
ledStat = false;
}else{
microcOut = (byte) (microcOut | 128);
btnled.setText(R.string.ledbuttonOFF);
ledStat = true;
}
write(microcOut);
}
});
}
/** Thread used to connect to a specified Bluetooth Device */
public class ConnectThread extends Thread {
private String address;
private boolean connectionStatus;
ConnectThread(String MACaddress) {
address = MACaddress;
connectionStatus = true;
}
public void run() {
// When this returns, it will 'know' about the server,
// via it's MAC address.
try {
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// We need two things before we can successfully connect
// (authentication issues aside): a MAC address, which we
// already have, and an RFCOMM channel.
// Because RFCOMM channels (aka ports) are limited in
// number, Android doesn't allow you to use them directly;
// instead you request a RFCOMM mapping based on a service
// ID. In our case, we will use the well-known SPP Service
// ID. This ID is in UUID (GUID to you Microsofties)
// format. Given the UUID, Android will handle the
// mapping for you. Generally, this will return RFCOMM 1,
// but not always; it depends what other BlueTooth services
// are in use on your Android device.
try {
btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
connectionStatus = false;
}
}catch (IllegalArgumentException e) {
connectionStatus = false;
}
// Discovery may be going on, e.g., if you're running a
// 'scan for devices' search from your handset's Bluetooth
// settings, so we call cancelDiscovery(). It doesn't hurt
// to call it, but it might hurt not to... discovery is a
// heavyweight process; you don't want it in progress when
// a connection attempt is made.
btAdapter.cancelDiscovery();
// Blocking connect, for a simple client nothing else can
// happen until a successful connection is made, so we
// don't care if it blocks.
try {
btSocket.connect();
} catch (IOException e1) {
try {
btSocket.close();
} catch (IOException e2) {
}
}
// Create a data stream so we can talk to server.
try {
outStream = btSocket.getOutputStream();
} catch (IOException e2) {
connectionStatus = false;
}
// Send final result
if (connectionStatus) {
mHandler.sendEmptyMessage(1);
}else {
mHandler.sendEmptyMessage(0);
}
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Show please wait dialog
myProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.pleaseWait), getResources().getString(R.string.makingConnectionString), true);
// Get the device MAC address
deviceAddress = data.getExtras().getString(DeviceList.EXTRA_DEVICE_ADDRESS);
// Connect to device with specified MAC address
mConnectThread = new ConnectThread(deviceAddress);
mConnectThread.start();
}else {
// Failure retrieving MAC address
Toast.makeText(this, R.string.macFailed, Toast.LENGTH_SHORT).show();
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled
} else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
}
public void write(byte data) {
if (outStream != null) {
try {
outStream.write(data);
} catch (IOException e) {
}
}
}
public void emptyOutStream() {
if (outStream != null) {
try {
outStream.flush();
} catch (IOException e) {
}
}
}
public void connect() {
// Launch the DeviceListActivity to see devices and do scan
Intent serverIntent = new Intent(this, DeviceList.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
}
public void disconnect() {
if (outStream != null) {
try {
outStream.close();
connectStat = false;
connect_button.setText(R.string.disconnected);
} catch (IOException e) {
}
}
}
private final SensorEventListener mSensorListener = new SensorEventListener() {
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
@Override
public void onSensorChanged(SensorEvent event) {
// Checks whether to send steering command or not
long date = System.currentTimeMillis();
if (date - lastWrite > MOVE_TIME) {
yAccel.setText(" " + event.values[1]);
xAccel.setText(" " + event.values[0]);
if (event.values[1] > 2.5) {
// Turn right
microcOut = (byte) (microcOut & 248);
microcOut = (byte) (microcOut | 4);
}else if (event.values[1] < -2.5) {
// Turn left
microcOut = (byte) (microcOut & 244);
microcOut = (byte) (microcOut | 8);
}else {
// Center the steering servo
microcOut = (byte) (microcOut & 240);
}
write(microcOut);
lastWrite = date;
}
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_accelerometer, menu);
return true;
}
public void onResume() {
super.onResume();
mySensorManager.registerListener(mSensorListener, accSensor, SensorManager.SENSOR_DELAY_GAME);
}
@Override
public void onDestroy() {
emptyOutStream();
disconnect();
if (mSensorListener != null) {
mySensorManager.unregisterListener(mSensorListener);
}
super.onDestroy();
myclip.release();
}
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
}
}
}
}
私は主題 (BluetoothChat、インターネット上の人々のプロジェクトなど) をすべて読みましたが、とても疲れています。どんな助けでも大歓迎です。
- 編集 -
入力ストリームをテキストビューに入れることができました。私の問題は、デバイス (マイクロコントローラーまたは PC) に接続しようとしているときに、アプリケーションが進行状況ダイアログでスタックし (デバイスに接続されていますが、進行状況ダイアログが消えない)、何かが来るのを待つことです。しばらくすると (5 ~ 6 秒など)、何かが入っていても動かなくなったままになり、強制的に閉じる必要があります。問題は、ハンドラーがスレッドを処理する方法にあると思います。デバッガーでは、すべてのスレッドが正常に実行される問題はありません。
私のコードの変更点は次のとおりです。 私の ConnectThread では: `/** 指定された Bluetooth デバイスへの接続に使用されるスレッド */ public class ConnectThread extends Thread { private String address; プライベート ブーリアン connectionStatus;
ConnectThread(String MACaddress) {
address = MACaddress;
connectionStatus = true;
}
public void run() {
// When this returns, it will 'know' about the server,
// via it's MAC address.
try {
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// We need two things before we can successfully connect
// (authentication issues aside): a MAC address, which we
// already have, and an RFCOMM channel.
// Because RFCOMM channels (aka ports) are limited in
// number, Android doesn't allow you to use them directly;
// instead you request a RFCOMM mapping based on a service
// ID. In our case, we will use the well-known SPP Service
// ID. This ID is in UUID (GUID to you Microsofties)
// format. Given the UUID, Android will handle the
// mapping for you. Generally, this will return RFCOMM 1,
// but not always; it depends what other BlueTooth services
// are in use on your Android device.
try {
btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
connectionStatus = false;
}
}catch (IllegalArgumentException e) {
connectionStatus = false;
}
// Discovery may be going on, e.g., if you're running a
// 'scan for devices' search from your handset's Bluetooth
// settings, so we call cancelDiscovery(). It doesn't hurt
// to call it, but it might hurt not to... discovery is a
// heavyweight process; you don't want it in progress when
// a connection attempt is made.
btAdapter.cancelDiscovery();
// Blocking connect, for a simple client nothing else can
// happen until a successful connection is made, so we
// don't care if it blocks.
try {
btSocket.connect();
} catch (IOException e1) {
try {
btSocket.close();
} catch (IOException e2) {
}
}
// Create a data stream so we can talk to server.
try {
outStream = btSocket.getOutputStream();
} catch (IOException e2) {
connectionStatus = false;
}
try{
inStream = btSocket.getInputStream();
}catch (IOException e2){
connectionStatus = false;
}
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (connectionStatus) {
try {
byte[] b = new byte[64]; // buffer store for the stream
// Read from the InputStream
bytes = inStream.read(b); // Get number of bytes and message in "buffer"
mHandler.obtainMessage(RECIEVE_MESSAGE, bytes, -1, b).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
// Send final result
if (connectionStatus) {
mHandler.obtainMessage(1);
}else {
mHandler.sendEmptyMessage(0);
}
}
}
` そして、私の onCreate メソッドの mHandler で:
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (myProgressDialog.isShowing()) {
myProgressDialog.dismiss();
}
// Check if bluetooth connection was made to selected device
if (msg.what == 1) {
// Set button to display current status
connectStat = true;
connect_button.setText(R.string.connected);
// Reset the BluCar
microcOut = 0;
ledStat = false;
write(microcOut);
}else if (msg.what == 2){
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("."); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
incoming.setText(sbprint); // update TextView
connectStat = true;
connect_button.setText(R.string.connected);
}else{
incoming.setText("Problem!");
}
}else {
// Connection failed
failToast.show();
}
}
};
もう 1 つ必要なのは、バッファーがいっぱいになったときにバッファーを空にする方法です。
PS: 助けてくれて本当にありがとう。