【问题标题】:Parcleable extra not there after starting activityParcleable extra 开始活动后不存在
【发布时间】:2016-09-25 10:37:45
【问题描述】:

我正在尝试实现 Parcleable,以便我可以将其添加为额外的(这是一项要求)。

这是SwinImage 类的精简版,它只显示相关细节,即派生自 Parcleable 的部分:

package com.example.kevin.imagemetadata;
import android.os.Parcel;
import android.os.Parcelable;

public class SwinImage implements Parcelable
{
    public SwinImage(String imageName, String location, String[] keywords, String imageDate, boolean share, String email, int rating)
    {
        update(imageName, location, keywords, imageDate, share, email, rating);
    }

    //A constructor for when we havent assigned any metadata.
    public SwinImage(String imageName)
    {
    }

    public void update(String imageName, String location, String[] keywords, String imageDate, boolean share, String email, int rating)
    {
    }

    @Override
    public String toString()
    {
    }

    private void storeImageDetails() {
    }

    @Override
    //We don't need it - but we are forced to due to interface.
    public int describeContents()
    {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags)
    {
        out.writeString(imageName);
        out.writeString(location);

        out.writeStringArray(keywords);

        out.writeString(imageDate);

        //Can write boolean array but not boolean...
        boolean[] temp = {share};

        out.writeBooleanArray(temp);
        out.writeString(email);

        out.writeInt(rating);
    }

    public static final Parcelable.Creator<SwinImage> CREATOR = new Parcelable.Creator<SwinImage>()
    {

        @Override
        public SwinImage createFromParcel(Parcel parcel)
        {
            return new SwinImage(parcel);
        }

        @Override
        public SwinImage[] newArray(int i)
        {
            return new SwinImage[i];
        }
    };

    //THE PRIVATE CONSTRUCTOR - FOR INTERNAL USE ONLY.
    private SwinImage(Parcel parcel)
    {
        imageName = parcel.readString();
        location = parcel.readString();

        parcel.readStringArray(keywords);

        imageDate = parcel.readString();

        boolean[] tempArr = new boolean[1];
        parcel.readBooleanArray(tempArr);
        share = tempArr[0];

        email = parcel.readString();
        rating = parcel.readInt();
    }

}

好的...所以,在调用类中,我这样做:

public void ClickedImage(View v)
{
    Intent i = new Intent(this, MetaDataActivity.class);

    switch (getResources().getResourceEntryName(v.getId()))
    {
        case "burgerView":
            i.putExtra("SENT_IMAGE", burger); //IT IMPLEMENTS PARCLEABLE THEREFORE WE CAN PASS IT WHERE IT LOOKS FOR A PARCEL
            break;
        case "pitaView":
            i.putExtra("SENT_IMAGE", pita);
            break;
        case "pizzaView":
            i.putExtra("SENT_IMAGE", pizza);
            break;
        case "steakView":
            i.putExtra("SENT_IMAGE", steak);
            break;
    }

    startActivityForResult(i, GET_AND_SET_METADATA_REQUEST);
}

我在最后设置了一个断点,确实可以看出它是正确的:

The Intent showing an Extra

但是,在获得它时:

@Override
protected void onCreate(Bundle savedInstanceState)
{
    Log.d("Does", "Does this work");

    Intent i;
    i = getIntent();
    image = i.getExtras().getParcelable("SENT_IMAGE");

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_meta_data);
}

它永远不存在。对image 的分配使程序崩溃,我无法通过调试器看到我的SwinImage 甚至存在于意图中。

我做错了什么?为什么会崩溃?我已经尝试了几个小时的解决方案(主要是改变了我分配的方式——一些“解决方案”已经阻止它崩溃,但是 image 被分配了一个空值)

谁能提供一些见解?谢谢。

编辑:

我尝试将getIntent 移动到onCreate 之后无济于事。

编辑#2:堆栈跟踪:

http://pastebin.com/raw/XJbPxHRv

以及steak 等的类型:

public class MainActivity extends AppCompatActivity {

    static final int GET_AND_SET_METADATA_REQUEST = 1;  // The request code
    SwinImage burger, pita, pizza, steak;

【问题讨论】:

  • 如果你遇到了崩溃,为什么不从设备的 logcat 中附加崩溃日志呢?还显示您的代码使用的变量类型(imagepizza 等)。
  • 嗨,谢谢@Serhio 我已经更新了 OP。

标签: java android android-intent parcelable


【解决方案1】:

在以Parcel 作为参数的SwinImage 构造函数中,您可以这样做:

parcel.readStringArray(keywords);

这会失败,因为它试图将String 的数组读入keywords,即null,因为你没有先初始化它。

当您调用readStringArray() 时,您会将一个对String 现有数组的引用传递给它,它将从Parcel 复制String 数组到该数组中。

请注意,readStringArray()writeStringArray() 只有在您传递给 writeStringArray() 的数组引用不是 null 并且如果您传递给 readStringArray() 的数组中的元素数量正好是与传递给 writeStringArray() 的数组中的元素数相同。

您应该使用没有这些限制的createStringArray() 而不是readStringArray()。像这样使用它:

keywords = parcel.createStringArray();

【讨论】:

    【解决方案2】:

    您不能在 super.onCreate() 之前调用 getIntent() - 那时没有可用的 Intent。

    将您的 super 呼叫移到 getIntent 呼叫之前。

    更新:

    在上述修复之后,您的堆栈跟踪会显示问题:

    NullPointerException: Attempt to get length of null array
    at android.os.Parcel.readStringArray(Parcel.java:1026)
    at com.example.kevin.imagemetadata.SwinImage.<init>(SwinImage.java:108)
    

    似乎keywordsnull,因此尝试从包裹中读取它会崩溃。 要么确保keywords 永远不会为空,要么放置一个布尔值来表示是否可以读取关键字。 另外,根据这个:How to use writeStringArray() and readStringArray() in a Parcel,您可能应该使用 createStringArray 而不是 readStringArray,这要简单得多。

    一般注意事项:您应始终仔细阅读崩溃堆栈跟踪,以更好地了解您的代码为何无法按预期运行,通常这是修复损坏代码的最佳方法。

    【讨论】:

    • 这不是真的。 getIntent() 甚至在 super.onCreate() 之前有效。 Activity 的意图在 onCreate() 回调之前被初始化。通常通过Activity.attach() 完成。详情请见here
    • 嗨,我把它移到super.onCreate() 之后,它仍然崩溃:(
    • 发布您的堆栈跟踪,intent 或 getExtras 为空。
    • 谢谢@marmor 我已经用堆栈跟踪更新了 OP。
    • 嗨!谢谢!它解决了我的问题,我确实投了赞成票,但在我达到 15 名声望之前它不会显示 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 2013-06-19
    • 1970-01-01
    相关资源
    最近更新 更多