java - Android BluetoothGattService - exception cannot marshall -
i have got following problem.
my application architecture more or less consits of 3 main parts:
- devices view (shows available ble devices)
- ble service (handles ble connections , data)
- services view (shows services particular device)
my issue passing bluetoothgattservice intent second time (first time works).
more or less actions this:
- choose device, want show services
- send intent device , action perform bleservice
- bleservice performs service discovery , sends intent services back
- broadcastreceiver receives intent , wats start new activity using data in received intent.
and on last step there problem cannot put arraylist intent/bundle causes exception:
e/androidruntime: fatal exception: main process: com.projects.dawid.gattclient, pid: 4133 java.lang.runtimeexception: parcel: unable marshal value android.bluetooth.bluetoothgattservice@ef62956 @ android.os.parcel.writevalue(parcel.java:1337) @ android.os.parcel.writelist(parcel.java:711) @ android.os.parcel.writevalue(parcel.java:1284) @ android.os.parcel.writearraymapinternal(parcel.java:638) @ android.os.basebundle.writetoparcelinner(basebundle.java:1313) @ android.os.bundle.writetoparcel(bundle.java:1096) @ android.os.parcel.writebundle(parcel.java:663) @ android.content.intent.writetoparcel(intent.java:7838) @ android.app.activitymanagerproxy.startactivity(activitymanagernative.java:2530)
for me it's very strange, if operation unsupported, exception on sending arraylist of services bleservice broadcastreceiver, not now.
source code:
bleservice broadcast receiver code
private void notifyservicesdiscovered(bluetoothgatt gatt) { intent intent = new intent(); intent.setaction(bleservice.response); intent.putextra(bleservice.response, bleservice.responses.services_discovered); intent.putextra(bleservice.responses.device, gatt.getdevice()); intent.putparcelablearraylistextra(bleservice.responses.services_list, getarraylistservices(gatt)); localbroadcastmanager.getinstance(mservicecontext).sendbroadcast(intent); } @nonnull private arraylist<bluetoothgattservice> getarraylistservices(bluetoothgatt gatt) { arraylist<bluetoothgattservice> services = new arraylist<>(); services.addall(gatt.getservices()); return services; }
this works fine. now
broadcast receiver new activity code
after recognizing proper intent handle method invoked
private void createviewwithservices(intent intent) { log.i(tag, "creating new activity!"); bluetoothdevice device = intent.getparcelableextra(bleservice.responses.device); arraylist<bluetoothgattservice> services = intent.getparcelablearraylistextra(bleservice.responses.services_list); intent serviceshowintent = new intent(mactivitycontext, serviceshowactivity.class); serviceshowintent.putextra(bleservice.responses.device, device); serviceshowintent.putparcelablearraylistextra(bleservice.responses.services_list, services); //this line causes error mactivitycontext.startactivity(serviceshowintent); // here exception thrown }
can explain me mistery lying behind this? cannot understand why first code fine, while second fails exception.
already tried doing things in lots of different ways, of them failed. exchanging bundles between intents contents same, failed, copying list items makes no difference.
edit
refering androidruntime error: parcel: unable marshal value error. difference is, using objects of classes provided android itself, bluetoothgattservice, implement parcelable interface refering https://developer.android.com/reference/android/bluetooth/bluetoothgattservice.html
there 2 issues in play here: 1 causes work fine when local broadcasts used, 1 makes serialization of bluetoothgattservice
fail.
in order pass data between 2 processes, must serialized (written parcel
). bundle contents serialized/deserialized lazily — long bundle
object not cross process boundaries or stored on disk, contained objects stored in memory (within hashmap) , won't serialized.
local broadcasts never cross process boundaries, not serialize/deserialize intent extras. inter-process communications (global broadcasts, asking activitymanager start activity) do.
in order passed between processes, intent extras must either parcelable or serializable, otherwise android may treat them opaque objects under circumstances, , attempt determine approach serialization (as serializable/parcelable/string etc.) @ runtime (see writevalue) — , fail.
as bluetoothgattservice — didn't implement parcelable after initial public release , was retroactively changed implement parcelable in api 24. means, there devices in wild, class not implement parcelable (even if in source code of latest android version). adding parent inheritance chain not technically breaking change far binary compatibility concerned — java classloaders won't complain. code, relies on parcelability of such class, either fail during bytecode validation or cause classcastexception/arraystoreexception on older versions.
java generics not reified — when compiled binary code, arraylist<string>
, arraylist<parcelable>
classloader same: arraylist<?>
. not casting bluetoothgattservice parcelable , neither arraylist (internally stores it's contents in object[]
). in order serialize arraylist, hashmap , similar classes, android have use reflection, , fails in case, because runtime type of bluetoothgattservice not implement parcelable on device. add code, explicitly makes cast (such placing bluetoothgattservice in parcelable[]
) , see.
also, on devices, happen implement parcelable prior api 24, trying serialize bluetoothgattservice still bad idea (that wasn't officially public api, wasn't covered cts, , untested).
i recommend refrain passing bluetoothgattservice via parcelization , find other way approach task (such passing it's contents or storing instance in singlton).
Comments
Post a Comment