我是 Java/Android 新手,正在尝试开发一个与 USB CAN 总线适配器通信的 adroid 应用程序。我通过我的 CANBusController 类以字符串形式从适配器接收消息,并且我构建了一个可打包类 CANMessage,它将接收到的字符串转换为我可以使用的形式(int Id、int Length、byte[] 数据)。现在我正在尝试显示我收到的消息。我有一个 fragment CANBusControlFragment,它声明了一个 BroadcastReceiver。当收到一条消息时,我构建我的 CANMessage,将它和它的字符串放入一个包中,将包放入一个 Intent 中,然后使用 sendBroadcast(intent):
CANBusController
{
public void handleMessage(Message msg)
{
Bundle bundle = msg.getData();
CANMessage canMsg = bundle.getParcelable("CAN_MESSAGE");
if (canMsg != null)
{
Intent intent = new Intent();
intent.setAction(BroadcastActions.CAN_MESSAGE_RECEIVED);
//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("CAN_MESSAGE", canMsg);
intent.putExtra("STRING_MESSAGE", canMsg.toString());
parentContext.sendBroadcast(intent);
}
}
}
CANBusControlFragment extends Fragment
{
private final BroadcastReceiver canMsgReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
Bundle bundle = intent.getExtras();
try
{
if (BroadcastActions.CAN_MESSAGE_RECEIVED.equals(action))
{
synchronized(this)
{
String str = bundle.getString("STRING_MESSAGE"); // <-- Crash
CANMessage canMsg = bundle.getParcelable("CAN_MESSAGE"); //
Append(str);
Append(canMsg.toString();
}
}
}
catch (Exception ex)
print exception
}
}
}
如果我将 CANMessage 添加到包中,当我尝试 getString 或 getParcelable 时,我的应用程序将在 BroadcastReceiver 的 onReceived 方法中崩溃并出现空指针异常。如果我不包含 CANMessage,则应用程序将正常工作。我相信 CANMessage 正确实现了 Parcelable,因为我已经通过执行除广播消息之外的所有相同步骤对其进行了测试:构建 CANMessage,将 Parcelable 放入 Bundle,将 Bundle 放入 Intent,从 Intent 中获取 Bundle,从 bundle 。
我很感激任何帮助。谢谢 :)
编辑 - LogCat 信息:
看来错误出在我的包裹方法中。尝试 readByteArray(byte[]) 会导致应用程序崩溃。
11-12 09:17:44.568: E/AndroidRuntime(3087): FATAL EXCEPTION: main
11-12 09:17:44.568: E/AndroidRuntime(3087): java.lang.RuntimeException: Error receiving broadcast Intent { act=com.sb2tablet.CAN_MESSAGE_RECEIVED flg=0x10000010 (has extras) } in com.sb2tablet.CANBusControlFragment$1@9e8f6e00
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:768)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Handler.handleCallback(Handler.java:725)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Handler.dispatchMessage(Handler.java:92)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Looper.loop(Looper.java:137)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.app.ActivityThread.main(ActivityThread.java:5041)
11-12 09:17:44.568: E/AndroidRuntime(3087): at java.lang.reflect.Method.invokeNative(Native Method)
11-12 09:17:44.568: E/AndroidRuntime(3087): at java.lang.reflect.Method.invoke(Method.java:511)
11-12 09:17:44.568: E/AndroidRuntime(3087): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
11-12 09:17:44.568: E/AndroidRuntime(3087): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
11-12 09:17:44.568: E/AndroidRuntime(3087): at dalvik.system.NativeStart.main(Native Method)
11-12 09:17:44.568: E/AndroidRuntime(3087): Caused by: java.lang.NullPointerException
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Parcel.readByteArray(Parcel.java:1594)
11-12 09:17:44.568: E/AndroidRuntime(3087): at com.sb2tablet.models.CANMessage.<init>(CANMessage.java:93)
11-12 09:17:44.568: E/AndroidRuntime(3087): at com.sb2tablet.models.CANMessage$1.createFromParcel(CANMessage.java:18)
11-12 09:17:44.568: E/AndroidRuntime(3087): at com.sb2tablet.models.CANMessage$1.createFromParcel(CANMessage.java:1)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Parcel.readParcelable(Parcel.java:2103)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Parcel.readValue(Parcel.java:1965)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Parcel.readMapInternal(Parcel.java:2226)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Bundle.unparcel(Bundle.java:223)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.os.Bundle.containsKey(Bundle.java:271)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.content.Intent.hasExtra(Intent.java:4121)
11-12 09:17:44.568: E/AndroidRuntime(3087): at com.sb2tablet.CANBusControlFragment$1.onReceive(CANBusControlFragment.java:51)
11-12 09:17:44.568: E/AndroidRuntime(3087): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:758)
编辑 - writeToParcel 和 Parcel 在:
public void writeToParcel(Parcel out, int flags)
{
out.writeValue(id); // int
out.writeValue(len); // int
out.writevalue(data); // byteArray, the value is not null here
//out.writeByArray(data);
}
public CANMessage(Parcel in)
{
id = in.readInt();
len = in.readInt();
in.readByteArray(data); // Actual crash is here
}
编辑 - 测试案例 1 - 我的包裹中似乎添加了额外的数据,我不确定如何。
public void writeToParcel(Parcel out, int flags)
{
out.writeValue(id); // int = 256
out.writeValue(len); // int = 2, length of byte array
out.writevalue(data); // byte array = { 17, 51 }
}
public CANMessage(Parcel in)
{
len = in.readInt(); // 1
id = in.readInt(); // 256
len = in.readInt(); // 1
len = in.readInt(); // 2
int i = in.readInt(); // 13
if (data == null) data = new byte[len];
in.readByteArray(data); // data = { 17, 51 }
}
编辑 - 测试用例 2
public void writeToParcel(Parcel out, int flags)
{
out.writeValue(id); // int = 256
out.writeValue(len); // int = 2, length of byte array
out.writeByteArray(data); // byte array = { 17, 51 }
}
public CANMessage(Parcel in)
{
len = in.readInt(); // 1
id = in.readInt(); // 256
len = in.readInt(); // 1
len = in.readInt(); // 2
len = in.readInt(); // 2
if (data == null) data = new byte[len];
// in.readByteArray(data); // Crashes
int i = in.readInt(); // 13073 = 0x3311 = byte[] { 17, 51 }
}
最佳答案
当您读取一个字节数组时,您需要事先分配一个(至少)正确大小的字节数组。像这样:
byte[] blah = new byte[100];
in.readByteArray(blah);
此外,您不想使用
writeValue()
将原语写入 Parcel
。使用适当的方法。例子:out.writeInt(id); // int = 256
out.writeInt(len); // int = 2, length of byte array
out.writeByteArray(data); // byte array = { 17, 51 }
您必须始终将
write()
方法与包裹上相同类型的 read()
方法配对。例如,如果您使用 writeValue()
将某些内容写入 Parcel
,则必须使用 readValue()
读取它。如果您知道变量是 int
,那么您应该使用 writeInt()
编写它并使用 readInt()
读取它。如果您使用 writeValue()
编写它,那么对象的“类型”也会写入 Parcel
以便 readValue()
知道它是什么类型的对象。这就是您在 Parcel
中看到额外数据的原因。