1

来自德国的问候!

今天我在尝试这样做时遇到了一个非常奇怪的问题:
位置->包裹->位置

我尝试使用以下方法从位置创建包裹:
location.writeToParcel(parcel, flags) 和
parcel.writeParcelable(location, flags)

并使用以下方法从这些包裹中检索位置:
parcel.readParcelable(Location.class.getClassLoader()) 和
Location.CREATOR.createFromParcel(parcel)

以下代码片段显示了从有效位置(参见代码的顶部)到包裹并返回到该位置的所有 4 种可能组合。但是,这两种方法都没有按预期工作,我想不出这里出了什么问题。

在尝试从包裹中检索位置后,日志的相关部分显示在注释中。

我从一个有效的位置开始,如下所示:

    import android.location.Location;
    import android.os.Parcel;
    [...]

    // locationList as arrived in a broadcast via FusedLocationProviderClient, locations are O.K.
    Location location = locationList.get(0);
    Timber.d("in: "+String.format("%.1f",location.getLatitude()) + "/" +
                    String.format("%.1f",(location.getLongitude())));
    //  result: "[...] in: 47,8/12,6" (<- just to demonstrate locations are fine at this point)

但是,我似乎没有从这个位置得到一个有效的包裹。

第一次尝试:使用 parcel.writeParcelable() 创建包裹

    Parcel parcel1 = Parcel.obtain();
    parcel1.writeParcelable(location, 0);

    Location location1a = parcel1.readParcelable(Location.class.getClassLoader());
    Timber.d("out1a: "+String.format("%.1f",location1a.getLatitude()) + "/" +
                       String.format("%.1f",(location1a.getLongitude())));
    // result: NullPointerException "[...] Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference"

    Location location1b = Location.CREATOR.createFromParcel(parcel1);
    Timber.d("out1b: "+String.format("%.1f",location1b.getLatitude()) + "/" +
                       String.format("%.1f",(location1b.getLongitude())));
    // result: "[...] out1b: 0,0/0,0"

我应该补充

  • parcel1 在调试器中的 parcel.writeParcelable() 之后看起来完全不变
  • 不仅经纬度为0,location1b内的所有数据

第二次尝试:使用 location.writeToParcel() 创建包裹

    Parcel parcel2 = Parcel.obtain();
    location.writeToParcel(parcel2, 0);

    Location location2a = parcel1.readParcelable(Location.class.getClassLoader());
    Timber.d("out2a: "+String.format("%.1f",location2a.getLatitude()) + "/" +
                       String.format("%.1f",(location2a.getLongitude())));
    // result: NullPointerException "... Attempt to invoke virtual method 'double android.location.Location.getLatitude()' on a null object reference"

    Location location2b = Location.CREATOR.createFromParcel(parcel2);
    Timber.d("out2b: "+String.format("%.1f",location2b.getLatitude()) + "/" +
                       String.format("%.1f",(location2b.getLongitude())));
    // result: "[...] out2b: 0,0/0,0"

再一次,location2b 中的所有数据都是 0,在我看来,在 location.writeToParcel() 之后 parcel2 也没有变化。

看起来有一些根本性的问题。知道它是什么吗?位置是否忘记了如何在夜间正确地将其状态保存到包裹中,或者我是否忘记了如何正确地包裹位置?

(使用安卓7.0的真机)

4

1 回答 1

2

好的,我现在可以回答我自己的问题了。

问题是,Location 从不调用
parcel.setDataPosition(0)。
在我看来,在阅读包裹之前应该在 Location 类中完成:

public static final Parcelable.Creator<Location> CREATOR =
    new Parcelable.Creator<Location>() {
    @Override
    public Location createFromParcel(Parcel in) {
        in.setDataPosition(0);            // this statement is missing!
        String provider = in.readString();
        Location l = new Location(provider);
        l.mTime = in.readLong();
        l.mElapsedRealtimeNanos = in.readLong();
        l.mFieldsMask = in.readByte();
        l.mLatitude = in.readDouble();
        l.mLongitude = in.readDouble();
        l.mAltitude = in.readDouble();
        l.mSpeed = in.readFloat();
        l.mBearing = in.readFloat();
        l.mHorizontalAccuracyMeters = in.readFloat();
        l.mVerticalAccuracyMeters = in.readFloat();
        l.mSpeedAccuracyMetersPerSecond = in.readFloat();
        l.mBearingAccuracyDegrees = in.readFloat();
        l.mExtras = Bundle.setDefusable(in.readBundle(), true);
        return l;
    }

然而,这不会发生。结果是,Location 仅从包裹中获取空值。

为了从包裹中获取我们的位置,我们需要手动重置包裹的数据位置。

import android.location.Location;
import android.os.Parcel;

// get a location from somewhere, then obtain the parcel 
Parcel parcel = Parcel.obtain();
location.writeToParcel(parcel, 0);    // or: parcel.writeParcelable(location, 0);

// send the parcel somewhere and retrieve the location like this:
parcel.setDataPosition(0);           // must be done before the location can be retrieved!
Location location = Location.CREATOR.createFromParcel(parcel);    // or: location = parcel.readParcelable(Location.class.getClassLoader());

这样一切正常。

感谢您抽出宝贵时间查看此问题!

于 2018-04-12T13:43:37.167 回答