我从http://www.elektor.com/magazines/2012/march/android-switch-interface.2084156.lynkx修改了一个示例蓝牙通信应用程序,使其与我的 Arduino 同步。
在做了一些小改动(如果是搜索栏,则改为按钮)后,我无法让它运行。我在手机上收到 FC 和错误,如下所示。
我是 android/java 新手,但已经编程多年。
我似乎无法通过在网上搜索 2 天来修复它。
11-13 18:41:58.127: E/AndroidRuntime(21448): java.lang.RuntimeException: Unable to start activity ComponentInfo{www.elektor.BTInterface/www.elektor.BTInterface.BluetoothChat}: android.util.AndroidRuntimeException: You cannot combine custom titles with other title features
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2185)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2210)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.ActivityThread.access$600(ActivityThread.java:140)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1206)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.os.Handler.dispatchMessage(Handler.java:99)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.os.Looper.loop(Looper.java:137)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.ActivityThread.main(ActivityThread.java:4906)
11-13 18:41:58.127: E/AndroidRuntime(21448): at java.lang.reflect.Method.invokeNative(Native Method)
11-13 18:41:58.127: E/AndroidRuntime(21448): at java.lang.reflect.Method.invoke(Method.java:511)
11-13 18:41:58.127: E/AndroidRuntime(21448): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
11-13 18:41:58.127: E/AndroidRuntime(21448): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
11-13 18:41:58.127: E/AndroidRuntime(21448): at dalvik.system.NativeStart.main(Native Method)
11-13 18:41:58.127: E/AndroidRuntime(21448): Caused by: android.util.AndroidRuntimeException: You cannot combine custom titles with other title features
11-13 18:41:58.127: E/AndroidRuntime(21448): at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:227)
11-13 18:41:58.127: E/AndroidRuntime(21448): at com.android.internal.policy.impl.PhoneWindow.generateLayout(PhoneWindow.java:2604)
11-13 18:41:58.127: E/AndroidRuntime(21448): at com.android.internal.policy.impl.PhoneWindow.installDecor(PhoneWindow.java:2844)
11-13 18:41:58.127: E/AndroidRuntime(21448): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:252)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.Activity.setContentView(Activity.java:1867)
11-13 18:41:58.127: E/AndroidRuntime(21448): at www.elektor.BTInterface.BluetoothChat.onCreate(BluetoothChat.java:101)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.Activity.performCreate(Activity.java:5008)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
11-13 18:41:58.127: E/AndroidRuntime(21448): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2139)
11-13 18:41:58.127: E/AndroidRuntime(21448): ... 11 more
11-13 18:42:02.872: I/Process(21448): Sending signal. PID: 21448 SIG: 9
这是我的代码和 xmls
/**
* This is the main Activity that displays the current chat session.
*/
public class BluetoothChat extends Activity {
// Debugging
private static final String TAG = "BluetoothChat";
private static final boolean D = true;
// Message types sent from the BluetoothChatService Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
// Key names received from the BluetoothChatService Handler
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
// Layout Views
private TextView mTitle;
private ListView mConversationView;
private EditText mOutEditText;
private WakeLock w1;
private String mConnectedDeviceName = null;
// Array adapter for the conversation thread
private ArrayAdapter<String> mConversationArrayAdapter;
// String buffer for outgoing messages
private StringBuffer mOutStringBuffer;
// Local Bluetooth adapter
private BluetoothAdapter mBluetoothAdapter = null;
// Member object for the chat services
private BluetoothRfcommClient mChatService = null;
// Activity mContext = null;
private int Servo1;
private int Servo2;
private int maxServo=120;
private Button sButton1;
private Button sButton2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(D) Log.e(TAG, "+++ ON CREATE +++");
// Set up the window layout
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.main);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);
// Set up the custom title
mTitle = (TextView) findViewById(R.id.title_left_text);
mTitle.setText(R.string.app_name);
mTitle = (TextView) findViewById(R.id.title_right_text);
sButton1 = (Button) findViewById(R.id.button1);
sButton2 = (Button) findViewById(R.id.button2);
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
}
@Override
public void onStart() {
super.onStart();
if(D) Log.e(TAG, "++ ON START ++");
// If BT is not on, request that it be enabled.
// setupChat() will then be called during onActivityResult
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
} else {
if (mChatService == null) setupChat();
}
}
@Override
public synchronized void onResume() {
super.onResume();
if(D) Log.e(TAG, "+ ON RESUME +");
// Performing this check in onResume() covers the case in which BT was
// not enabled during onStart(), so we were paused to enable it...
// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothRfcommClient.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
}
private void setupChat() {
Log.d(TAG, "setupChat()");
// Initialize the array adapter for the conversation thread
mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
mConversationView = (ListView) findViewById(R.id.in);
mConversationView.setAdapter(mConversationArrayAdapter);
// Initialize the BluetoothChatService to perform bluetooth connections
mChatService = new BluetoothRfcommClient(this, mHandler);
// Initialize the buffer for outgoing messages
mOutStringBuffer = new StringBuffer("");
}
@Override
public synchronized void onPause() {
super.onPause();
if(D) Log.e(TAG, "- ON PAUSE -");
//w1.release();
}
@Override
public void onStop() {
super.onStop();
if(D) Log.e(TAG, "-- ON STOP --");
}
@Override
public void onDestroy() {
super.onDestroy();
// Stop the Bluetooth chat services
if (mChatService != null) mChatService.stop();
if(D) Log.e(TAG, "--- ON DESTROY ---");
}
private void ensureDiscoverable() {
if(D) Log.d(TAG, "ensure discoverable");
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
/**
* Sends a message.
* @param message A string of text to send.
*/
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothRfcommClient.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
mChatService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
}
// The action listener for the EditText widget, to listen for the return key
// The Handler that gets information back from the BluetoothChatService
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothRfcommClient.STATE_CONNECTED:
mTitle.setText(R.string.title_connected_to);
mTitle.append(mConnectedDeviceName);
mConversationArrayAdapter.clear();
break;
case BluetoothRfcommClient.STATE_CONNECTING:
mTitle.setText(R.string.title_connecting);
break;
//case BluetoothRfcommClient.STATE_LISTEN:
case BluetoothRfcommClient.STATE_NONE:
mTitle.setText(R.string.title_not_connected);
break;
}
break;
case MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer
String writeMessage = new String(writeBuf);
mConversationArrayAdapter.add("Me: " + writeMessage);
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
UpdateScreen(readMessage);
// INSERT READING SWICTH
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(D) Log.d(TAG, "onActivityResult " + resultCode);
switch (requestCode) {
case REQUEST_CONNECT_DEVICE_SECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
connectDevice(data, true);
}
break;
case REQUEST_CONNECT_DEVICE_INSECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
connectDevice(data, false);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
setupChat();
} else {
// User did not enable Bluetooth or an error occured
Log.d(TAG, "BT not enabled");
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
}
private void connectDevice(Intent data, boolean secure) {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BLuetoothDevice object
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(device);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.option_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent serverIntent = null;
switch (item.getItemId()) {
case R.id.secure_connect_scan:
// Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
return true;
case R.id.insecure_connect_scan:
// Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
return true;
case R.id.discoverable:
// Ensure this device is discoverable by others
ensureDiscoverable();
return true;
}
return false;
}
private void UpdateScreen(String txtMessage) {
}
public void onServoButtonClick(View view) {
switch (view.getId()){
case R.id.button1:
if (Servo1 < maxServo){
Servo1++;
sendMessage("P,"+Servo1);
}
case R.id.button2:
if (Servo1 > 0){
Servo1--;
sendMessage("P,"+Servo1);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/GridLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="2"
android:orientation="horizontal" >
<ListView
android:id="@+id/in"
android:layout_height="62dp"
android:layout_column="0"
android:layout_gravity="fill_horizontal"
android:layout_row="0"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll" />
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_column="0"
android:layout_gravity="left"
android:layout_row="1"
android:text="@string/servo_1_up" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_column="0"
android:layout_gravity="left"
android:layout_row="2"
android:text="@string/servo_1_down" />
</GridLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0" package="www.elektor.BTInterface">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<application android:label="@string/app_name"
android:icon="@drawable/app_icon" >
<activity android:name=".BluetoothChat"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden" android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="www.elektor.BTInterface.DeviceListActivity"
android:label="@string/select_device"
android:theme="@android:style/Theme.Dialog"
android:configChanges="orientation|keyboardHidden" />
</application>
</manifest>