I have a strange issue going on, I have created an Android service, and a widget that consumes it. I have some complex objects that are sent between the two via AIDL. I have no problems registering my callbacks, and the service is populating the data correctly and sending it to the callbacks, but when I put a breakpoint on the writeToParcel method, and activate my debugger on the widget, I notice that the method is serializing the default class values, and not the ones the service populated it with. Does anyone have any suggestions for figuring out what is going on.
Here is my object:
Node.java:
package my.unique.package.name.service;
import java.util.ArrayList;
import java.util.HashMap;
import android.os.Parcel;
import android.os.Parcelable;
public class Node implements Parcelable {
protected int mNodeId;
protected double mBatteryLevel = -1;
protected double mBatteryTemp;
protected String mRadioName;
protected String mIPAddress;
protected String mFirmwareVersion;
protected String mModel;
protected String mSerialNumber;
protected String mUptime;
protected double mTemp;
protected double mInputVoltage;
protected double mBatteryClockVoltage;
protected String mSource;
protected double mLatitude;
protected double mLongitude;
protected double mAltitude;
protected String mFixType;
protected int mSatellites;
protected String mNTPServer;
protected ArrayList<Neighbor> mNeighbors;
protected HashMap<String, String> mManagedNodes;
protected HashMap<String, String> mOtherNodes;
public Node()
{
}
/**
* Node Constructor for Parcelable Interface
*
* @param in
* Parcel in
*/
public Node(Parcel in) {
String[] data = new String[19];
in.readStringArray(data);
mNodeId = Integer.parseInt(data[0]);
mBatteryLevel = Double.parseDouble(data[1]);
mBatteryTemp = Double.parseDouble(data[2]);
mRadioName = data[3];
mIPAddress = data[4];
mFirmwareVersion = data[5];
mModel = data[6];
mSerialNumber = data[7];
mUptime = data[8];
mTemp = Double.parseDouble(data[9]);
mInputVoltage = Double.parseDouble(data[10]);
mBatteryClockVoltage = Double.parseDouble(data[11]);
mSource = data[12];
mLatitude= Double.valueOf(data[13]);
mLongitude = Double.valueOf(data[14]);
mAltitude = Double.valueOf(data[15]);
mFixType = data[16];
mSatellites = Integer.valueOf(data[17]);
mNTPServer = data[18];
}
//Removed public get/set methods...
public static final Parcelable.Creator<Node> CREATOR = new Parcelable.Creator<Node>() {
public Node createFromParcel(Parcel in) {
return new Node(in);
}
public Node[] newArray(int size) {
return new Node[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] { String.valueOf(mNodeId),
String.valueOf(mBatteryLevel), String.valueOf(mBatteryTemp),
mRadioName, mIPAddress, mFirmwareVersion, mModel,
mSerialNumber, mUptime, String.valueOf(mTemp),
String.valueOf(mInputVoltage),
String.valueOf(mBatteryClockVoltage),
mSource, String.valueOf(mLatitude), String.valueOf(mLongitude),
String.valueOf(mAltitude), mFixType,
String.valueOf(mSatellites), mNTPServer});
}
}
Node.aidl:
package my.unique.package.namespace.service;
parcelable Node;
This is how the service notifies callbacks
private void notifyCallbacksOfUpdate(Node updated) {
final int N = mNodeUpdatedCallbacks.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
mNodeUpdatedCallbacks.getBroadcastItem(i).NodeUpdated(updated);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mNodeUpdatedCallbacks.finishBroadcast();
}
EDIT: Additional Code from consumer
MyApplication.java
public void bindConnection()
{
if (mServiceConnection == null) {
// create connection to service
mServiceConnection = new MyServiceConnection(this);
Intent i = new Intent("my.unique.package.IService");
boolean bound = bindService(i, mConnection,
Context.BIND_AUTO_CREATE);
Log.v("Service Bound: ", String.valueOf(bound));
}
}
Connection Class
import my.unique.package.service.IService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
public class MyServiceConnection implements ServiceConnection {
private IService service;
private Context mContext;
public MyServiceConnection(Context context)
{
mContext = context;
}
public void onServiceConnected(ComponentName name, IBinder boundService) {
service = IService.Stub.asInterface(boundService);
if(service != null)
{
mContext.sendBroadcast(new Intent(MyApplication.BOUND_TO_SERVICE));
}
}
public void onServiceDisconnected(ComponentName name) {
service = null;
}
protected IService getService()
{
return service;
}
}
In here is where I get notified of updates to the node, service sends correct info, but here is where it receives the default values. The node object class is in the same jar as the service and widget, just different packages, does the AIDL need to be copied to all of the packages, or can it reference it cross packages.
private INodeUpdatedCallback nodeUpdated = new INodeUpdatedCallback.Stub() {
@Override
public void NodeUpdated(Node nodeInfo) throws RemoteException {
Log.v("Node Updated: ", nodeInfo.getRadioIP());
if (nodeInfo.getIP().equalsIgnoreCase(mIp)
&& requestedLogin) {
requestedLogin = false;
ViewSwitcher vs = (ViewSwitcher) findViewById(R.id.vsSettings);
if (vs.getDisplayedChild() != VIEW_SETTINGS) {
vs.setInAnimation(AnimationUtils.loadAnimation(
WaveRelaySettingsActivity.this, R.anim.fade_in));
vs.setOutAnimation(AnimationUtils.loadAnimation(
WaveRelaySettingsActivity.this, R.anim.fade_out));
vs.setDisplayedChild(VIEW_SETTINGS);
}
}
}
};
Aidl for stub of callback
package my.unique.namespace.service;
import my.unique.namespace.service.Node;
oneway interface INodeUpdatedCallback {
void NodeUpdated(out Node nodeInfo);
}