Android Parcelable 对象在活动之间传递不正确

3

过去两天,这一直让我苦恼。奇怪的是,在一个项目中,当从活动传递对象到片段时,代码可以正常运行,但即使我看起来正确地实现了parcelable,我也不能将此对象从活动传递到活动。

奇怪的是,我在另一端没有得到一个空对象,但对象内部的值为null。

我创建了一个新项目来测试这个问题。到目前为止,这是代码:

MainActivity.java:

    package com.example.parcleableexample;

    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Intent;
    import android.view.Menu;
    import android.view.View;
    import android.widget.TextView;

    public class MainActivity extends Activity {
        Site mySite = new Site();


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mySite.setSiteName("hi");
            TextView myText = (TextView) findViewById(R.id.txtSiteName);
            myText.setText(mySite.getSiteName());
        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }


        public void doThing (View v) {
            Intent mIntent = new Intent(this,AnotherActivity.class);
            mIntent.putExtra("site", mySite);
            startActivity(mIntent);
        }
    }

AnotherActivity.java:

package com.example.parcleableexample;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.TextView;

public class AnotherActivity extends Activity {

    Site mySite = new Site();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mySite = getIntent().getParcelableExtra("site");
            TextView myText = (TextView) findViewById(R.id.txtSiteName);
            myText.setText(mySite.getSiteName());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

Site.Java:

package com.example.parcleableexample;

import android.os.Parcel;
import android.os.Parcelable;

public class Site implements Parcelable {

    private String siteName;

    Site() {
        // Empty Constructor
    }

    public String getSiteName() {
        return siteName;
    }

    public void setSiteName(String siteName) {
        this.siteName = siteName;
    }

    // Parcleable Functions:
    private int mData;
    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mData);
    }

    public static final Parcelable.Creator<Site> CREATOR = new Parcelable.Creator<Site>() {
        public Site createFromParcel(Parcel in) {
            return new Site(in);
        }

        public Site[] newArray(int size) {
            return new Site[size];
        }
    };

    private Site(Parcel in) {
        mData = in.readInt();
    }
}

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/txtSiteName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/txtSiteName"
        android:layout_below="@+id/txtSiteName"
        android:layout_marginLeft="42dp"
        android:layout_marginTop="25dp"
        android:onClick="doThing"
        android:text="Button" />

</RelativeLayout>

我希望看到的是,“hi”值在我启动应用程序时和点击按钮创建新活动时都出现。

然而,第二次只有第一次正确显示,第二次getSiteName只返回null。

我还直接从工作应用程序中复制并粘贴了Site对象,结果相同,但它在工作应用程序中按预期工作;Site对象被正确复制。

工作中的应用程序运行此代码:

Bundle arguments = new Bundle();
arguments.putParcelable("site", SearchResults.get(position));
ViewSiteFragment myFragment = new ViewSiteFragment();
myFragment.setArguments(arguments);
FragmentTransaction myTransaction = getFragmentManager().beginTransaction();
myTransaction.replace(R.id.MainFragmentContainer, myFragment);
myTransaction.addToBackStack(null);
myTransaction.commit();

在这里,它捡起了另一端的对象:
Site mSite = getArguments().getParcelable("site");

我知道我在做错什么……只是不知道我错过了什么!

相关的 IT 技术问题。

1
最重要的类Site在哪里? - pskink
你从/向“mData”读写,但它在任何地方都没有被使用,这有任何意义吗? - pskink
不是的。但这就是我为什么感到困惑的原因,为什么代码在我的其他项目中完美运行?mData是我在stackoverflow上找到的代码。我真的需要在这些块中获取和设置每个值吗? - Ribs
@pskink 好的,我搞定了,多亏了你,pskink。正如你所说,mData 是无意义的,没有任何作用。我应该在 writeToParcel/private Site(Parcel in) 行上正确地设置/获取 Site 对象的值。我仍然完全不知道为什么其他项目可以正常使用这个代码,我猜可能是我有内存泄漏,或者我做了一些非常奇怪的事情... - Ribs
使用片段时,由于在调用getArguments时获取的是调用setArguments时使用的相同对象,因此它可以正常工作。使用hashCode()来验证这一点。 - pskink
显示剩余2条评论
2个回答

4
问题出在您Parcelable的实现上。siteName从未写入包中,而您却写入了mData,而这在任何地方都没有被使用。如果需要,可以保留mData,并为siteName ADD写入代码。请参看以下代码:
public void writeToParcel(Parcel out, int flags) {
    out.writeInt(mData);

    //we want to keep siteName in our parcel, so let's write it to the Parcel obj
    out.writeString(siteName);
}

稍后,将此代码添加到读取包裹的代码中:
private Site(Parcel in) {
    mData = in.readInt();

    //let's read from in Parcel an set our siteName
    siteName = in.readString();
}

0

使用bundle对象接收它:

在activity2中,在onCreate()方法中,您可以通过检索bundle(其中包含调用活动发送的所有消息)并调用以下方法来获取String消息/对象:

Bundle bundle = getIntent().getExtras();
mySite = bundle.getParcelableExtra("site");

getParcleableExtra 似乎不存在。 使用 Bundle bundle = getIntent().getExtras(); mySite = bundle.getParcelable("site"); TextView myText = (TextView) findViewById(R.id.txtSiteName); myText.setText(mySite.getSiteName()); 结果相同,getSiteName() 没有返回任何文本。 - Ribs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接