【问题标题】:Cannot parcel a Location无法打包位置
【发布时间】:2023-03-21 14:10:01
【问题描述】:

来自德国的问候!

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

我尝试使用以下方法从某个位置创建地块:
location.writeToParcel(parcel, flags) 和
parcel.writeParcelable(位置,标志)

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

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

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

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

    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内的所有数据都为0

第二次尝试:使用 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 也没有变化。

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

(使用搭载 Android 7.0 的真实设备)

【问题讨论】:

    标签: android location parcelable parcel fusedlocationproviderclient


    【解决方案1】:

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

    问题是,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());
    

    这样一切正常。

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

    【讨论】:

    • 我不知道其他人是怎么遇到这种情况的,但是你在这个问题上救了我。非常感谢。
    • setDataPositon(0) 不存在的原因是Location 可能是包含其他数据的较大包裹的一部分。 FWIW,我存储Parcel 而不是Location 本身的用例是我在存储Locations 后在我脚下更新它们时遇到了麻烦。我现在存储包含位置的Parcels,因此它们无法更改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    相关资源
    最近更新 更多