I\'m trying to serialize my location class (using android.location class)
but, it gives me an error!
11-21 21:25:37.337: W/System.err(3152): java.io.
I needed to serialize Location
with most of it's members as well, not just latitude and longitude. I ended up writing my own Serializable
class. The source code is bellow. The usage would be:
SerializableLocation serializable = new SerializableLocation(fromLocation);
Location toLocation = serializable.toLocation();
Few notes:
Location
's extras (Bundle
) are not serializedLocation
coming from mock provider or not is lost. Location.setIsFromMockProvider
can be called only by the system.Here is the source code:
import android.location.Location;
import android.os.Build;
import androidx.annotation.NonNull;
import java.io.Serializable;
public class SerializableLocation implements Serializable {
private static final long serialVersionUID = 1L;
private static final int HAS_ALTITUDE_MASK = 1;
private static final int HAS_SPEED_MASK = 2;
private static final int HAS_BEARING_MASK = 4;
private static final int HAS_HORIZONTAL_ACCURACY_MASK = 8;
private static final int HAS_MOCK_PROVIDER_MASK = 16;
private static final int HAS_VERTICAL_ACCURACY_MASK = 32;
private static final int HAS_SPEED_ACCURACY_MASK = 64;
private static final int HAS_BEARING_ACCURACY_MASK = 128;
private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 256;
private String provider;
private long time = 0;
private long elapsedRealtimeNanos = 0;
private double elapsedRealtimeUncertaintyNanos = 0.0f;
private double latitude = 0.0;
private double longitude = 0.0;
private double altitude = 0.0f;
private float speed = 0.0f;
private float bearing = 0.0f;
private float horizontalAccuracyMeters = 0.0f;
private float verticalAccuracyMeters = 0.0f;
private float speedAccuracyMetersPerSecond = 0.0f;
private float bearingAccuracyDegrees = 0.0f;
private int fieldsMask = 0;
// private Bundle extras = null;
private boolean hasElapsedRealtimeUncertaintyNanos() {
return (fieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0;
}
private boolean hasAltitude() {
return (fieldsMask & HAS_ALTITUDE_MASK) != 0;
}
private boolean hasSpeed() {
return (fieldsMask & HAS_SPEED_MASK) != 0;
}
private boolean hasBearing() {
return (fieldsMask & HAS_BEARING_MASK) != 0;
}
private boolean hasAccuracy() {
return (fieldsMask & HAS_HORIZONTAL_ACCURACY_MASK) != 0;
}
private boolean hasVerticalAccuracy() {
return (fieldsMask & HAS_VERTICAL_ACCURACY_MASK) != 0;
}
private boolean hasSpeedAccuracy() {
return (fieldsMask & HAS_SPEED_ACCURACY_MASK) != 0;
}
private boolean hasBearingAccuracy() {
return (fieldsMask & HAS_BEARING_ACCURACY_MASK) != 0;
}
private boolean isFromMockProvider() {
return (fieldsMask & HAS_MOCK_PROVIDER_MASK) != 0;
}
public SerializableLocation(@NonNull Location l) {
provider = l.getProvider();
time = l.getTime();
elapsedRealtimeNanos = l.getElapsedRealtimeNanos();
latitude = l.getLatitude();
longitude = l.getLongitude();
if (l.hasAltitude()) {
altitude = l.getAltitude();
fieldsMask |= HAS_ALTITUDE_MASK;
}
if (l.hasSpeed()) {
speed = l.getSpeed();
fieldsMask |= HAS_SPEED_MASK;
}
if (l.hasBearing()) {
bearing = l.getBearing();
fieldsMask |= HAS_BEARING_MASK;
}
if (l.hasAccuracy()) {
horizontalAccuracyMeters = l.getAccuracy();
fieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (l.hasVerticalAccuracy()) {
verticalAccuracyMeters = l.getVerticalAccuracyMeters();
fieldsMask |= HAS_VERTICAL_ACCURACY_MASK;
}
if (l.hasSpeedAccuracy()) {
speedAccuracyMetersPerSecond =
l.getSpeedAccuracyMetersPerSecond();
fieldsMask |= HAS_SPEED_ACCURACY_MASK;
}
if (l.hasBearingAccuracy()) {
bearingAccuracyDegrees = l.getBearingAccuracyDegrees();
fieldsMask |= HAS_BEARING_ACCURACY_MASK;
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (l.hasElapsedRealtimeUncertaintyNanos()) {
elapsedRealtimeUncertaintyNanos =
l.getElapsedRealtimeUncertaintyNanos();
fieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
}
}
if (l.isFromMockProvider()) {
fieldsMask |= HAS_MOCK_PROVIDER_MASK;
}
}
public Location toLocation() {
Location l = new Location(provider);
l.setTime(time);
l.setElapsedRealtimeNanos(elapsedRealtimeNanos);
l.setLatitude(latitude);
l.setLongitude(longitude);
if (hasAltitude()) {
l.setAltitude(altitude);
}
if (hasSpeed()) {
l.setSpeed(speed);
}
if (hasBearing()) {
l.setBearing(bearing);
}
if (hasAccuracy()) {
l.setAccuracy(horizontalAccuracyMeters);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (hasVerticalAccuracy()) {
l.setVerticalAccuracyMeters(verticalAccuracyMeters);
}
if (hasSpeedAccuracy()) {
l.setSpeedAccuracyMetersPerSecond(speedAccuracyMetersPerSecond);
}
if (hasBearingAccuracy()) {
l.setBearingAccuracyDegrees(bearingAccuracyDegrees);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (hasElapsedRealtimeUncertaintyNanos()) {
l.setElapsedRealtimeUncertaintyNanos(
elapsedRealtimeUncertaintyNanos
);
}
}
// l.setIsFromMockProvider(isFromMockProvider());
return l;
}
}
Android's Location class already implements Parcelable
. So you are better off with it rather than implementing your own Serialization.
Simply use the following to get bytes
out from Location
:
Parcel p = Parcel.obtain();
objLocation.writeToParcel(p, 0);
final byte[] b = p.marshall(); //now you've got bytes
p.recycle();
However, you should not save bytes (in persistent storage) from Parecelable
object for later use because it is designed for high-performance IPC transport, and is not a general-purpose serialization mechanism.
You can not make a non-serializable class serializable just implementing the Serializable interface. A serializable class must inherit from a serializable class (if an inherited class) and have all its attributes serializable themselves.
All subtypes of a serializable class are themselves serializable. http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
However, if you want to serialize a Parcelable class it is still possible, but surely it would not be a good practice.