Java 在Android中作为结果(而不是原始类)返回时,实现列表反序列化为ArrayList的对象

Java 在Android中作为结果(而不是原始类)返回时,实现列表反序列化为ArrayList的对象,java,android,android-intent,serialization,onactivityresult,Java,Android,Android Intent,Serialization,Onactivityresult,我正在开发一款Android应用程序,用户可以使用手机摄像头扫描合同。当我希望用户添加新合同时,我会启动一个活动,让他们拍摄合同不同页面的大量图片(第二个活动通过使用MediaStore.ACTION\u IMAGE\u CAPTUREintent来完成)。这似乎很好,我尝试通过setResult()返回已完成的合同对象,并通过onActivityResult()在MainActivity中检索它: 但是,Contract对象未正确反序列化,这导致应用程序在返回到MainActivity时发生C

我正在开发一款Android应用程序,用户可以使用手机摄像头扫描合同。当我希望用户添加新合同时,我会启动一个活动,让他们拍摄合同不同页面的大量图片(第二个活动通过使用
MediaStore.ACTION\u IMAGE\u CAPTURE
intent来完成)。这似乎很好,我尝试通过
setResult()
返回已完成的合同对象,并通过
onActivityResult()在MainActivity中检索它:

但是,
Contract
对象未正确反序列化,这导致应用程序在返回到
MainActivity
时发生ClassCastException崩溃(在我将其转换为
Contract
的行中):

02-06 23:10:53.891: W/dalvikvm(15398): threadid=1: thread exiting with uncaught exception (group=0x41910700)
02-06 23:10:53.907: E/AndroidRuntime(15398): FATAL EXCEPTION: main
02-06 23:10:53.907: E/AndroidRuntime(15398): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { (has extras) }} to activity {myapp/myapp.EndkundenMainActivity}: java.lang.ClassCastException: java.util.ArrayList cannot be cast to mylib.model.Contract
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3367)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3410)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.app.ActivityThread.access$1100(ActivityThread.java:141)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1304)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.os.Handler.dispatchMessage(Handler.java:99)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.os.Looper.loop(Looper.java:137)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.app.ActivityThread.main(ActivityThread.java:5103)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at java.lang.reflect.Method.invokeNative(Native Method)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at java.lang.reflect.Method.invoke(Method.java:525)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at dalvik.system.NativeStart.main(Native Method)
02-06 23:10:53.907: E/AndroidRuntime(15398): Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to mylib.model.Contract
02-06 23:10:53.907: E/AndroidRuntime(15398):    at de.kreditpruefen.lib.MainActivity.onActivityResult(MainActivity.java:232)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.app.Activity.dispatchActivityResult(Activity.java:5322)
02-06 23:10:53.907: E/AndroidRuntime(15398):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3363)
02-06 23:10:53.907: E/AndroidRuntime(15398):    ... 11 more
我的
Contract
对象只是
ContractPage
s的集合,因此我声明它实现
List
如下:

public class Contract implements Serializable, List<ContractPage>
然后像这样恢复它:

@Override
protected void onSaveInstanceState(Bundle outState)
{
    outState.putSerializable(EXTRA_CONTRACT, this.contract);
    super.onSaveInstanceState(outState);
}
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null)
    {
        this.contract = (Contract) savedInstanceState.get(EXTRA_CONTRACT);
    }
}
这不应该导致它也被序列化和反序列化吗?为什么在这种情况下有效,但在活动之间转移对象时无效?

完成以下部分相关代码:

MainActivity.java

public class MainActivity extends Activity
{
    private static final int REQUEST_CONTRACT = 1;

    private Contract contract;

    public void addContract(View view)
    {
        Intent intent = new Intent(this, ContractActivity.class);
        intent.putExtra(ContractActivity.EXTRA_CONTRACT, this.contract);
        startActivityForResult(intent, MainActivity.REQUEST_CONTRACT);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent)
    {
        if ((requestCode == REQUEST_CONTRACT) && (resultCode == RESULT_OK))
        {
            this.contract = (Contract) intent.getSerializableExtra(ContractActivity.EXTRA_CONTRACT);   
        }
        super.onActivityResult(requestCode, resultCode, intent);
    }
}
public class ContractActivity extends Activity
{
    public static final String EXTRA_CONTRACT = "ContractKey";
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null)
        {
            this.contract = (Contract) savedInstanceState.get(EXTRA_CONTRACT);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        outState.putSerializable(EXTRA_CONTRACT, this.contract);
        super.onSaveInstanceState(outState);
    }

    /**
     * Set up the {@link android.app.ActionBar}.
     */
    private void setupActionBar()
    {
        getActionBar().setDisplayHomeAsUpEnabled(true);
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch (item.getItemId())
        {
            case android.R.id.home:
                // This ID represents the Home or Up button. In the case of this
                // activity, the Up button is shown. Use NavUtils to allow users
                // to navigate up one level in the application structure. For
                // more details, see the Navigation pattern on Android Design:
                //
                // http://developer.android.com/design/patterns/navigation.html#up-vs-back
                //

                Intent result = new Intent();
                result.putExtra(EXTRA_CONTRACT, this.contract);
                setResult(Activity.RESULT_OK, result);
                // use finish instead of navigateUp which ensures the same instance
                // of the calling activity is restarted which should cause the form
                // in the MainActivity to retain entered text etc.
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    // [...]
    // other methods that add pages to this.contract
}
public class Contract implements Serializable, List<ContractPage>
{
    private List<ContractPage> pages;

    private static final long serialVersionUID = -708359261524732081L;

    public Contract()
    {
        this.pages = new ArrayList<ContractPage>();
    }

    // [...]
    // implementations of all the other methods required by the List interface by delegating the method calls to this.pages
}
public class ContractPage implements Serializable
{

    private static final long serialVersionUID = 2721152546839021601L;

    private transient Bitmap image;
    private File imagePath;
    private transient Bitmap thumbnail;
    private int thumbnailWidthAndHeight;

    public ContractPage(File imagePath, int thumbnailWidthAndHeight)
    {
        this.imagePath = imagePath;
        this.thumbnailWidthAndHeight = thumbnailWidthAndHeight;
    }

    // [...]
    // getters and setters for the instance variables. image and thumbnail are lazy loaded from the imagePath.
}
ContractActivity.java

public class MainActivity extends Activity
{
    private static final int REQUEST_CONTRACT = 1;

    private Contract contract;

    public void addContract(View view)
    {
        Intent intent = new Intent(this, ContractActivity.class);
        intent.putExtra(ContractActivity.EXTRA_CONTRACT, this.contract);
        startActivityForResult(intent, MainActivity.REQUEST_CONTRACT);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent)
    {
        if ((requestCode == REQUEST_CONTRACT) && (resultCode == RESULT_OK))
        {
            this.contract = (Contract) intent.getSerializableExtra(ContractActivity.EXTRA_CONTRACT);   
        }
        super.onActivityResult(requestCode, resultCode, intent);
    }
}
public class ContractActivity extends Activity
{
    public static final String EXTRA_CONTRACT = "ContractKey";
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null)
        {
            this.contract = (Contract) savedInstanceState.get(EXTRA_CONTRACT);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        outState.putSerializable(EXTRA_CONTRACT, this.contract);
        super.onSaveInstanceState(outState);
    }

    /**
     * Set up the {@link android.app.ActionBar}.
     */
    private void setupActionBar()
    {
        getActionBar().setDisplayHomeAsUpEnabled(true);
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch (item.getItemId())
        {
            case android.R.id.home:
                // This ID represents the Home or Up button. In the case of this
                // activity, the Up button is shown. Use NavUtils to allow users
                // to navigate up one level in the application structure. For
                // more details, see the Navigation pattern on Android Design:
                //
                // http://developer.android.com/design/patterns/navigation.html#up-vs-back
                //

                Intent result = new Intent();
                result.putExtra(EXTRA_CONTRACT, this.contract);
                setResult(Activity.RESULT_OK, result);
                // use finish instead of navigateUp which ensures the same instance
                // of the calling activity is restarted which should cause the form
                // in the MainActivity to retain entered text etc.
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    // [...]
    // other methods that add pages to this.contract
}
public class Contract implements Serializable, List<ContractPage>
{
    private List<ContractPage> pages;

    private static final long serialVersionUID = -708359261524732081L;

    public Contract()
    {
        this.pages = new ArrayList<ContractPage>();
    }

    // [...]
    // implementations of all the other methods required by the List interface by delegating the method calls to this.pages
}
public class ContractPage implements Serializable
{

    private static final long serialVersionUID = 2721152546839021601L;

    private transient Bitmap image;
    private File imagePath;
    private transient Bitmap thumbnail;
    private int thumbnailWidthAndHeight;

    public ContractPage(File imagePath, int thumbnailWidthAndHeight)
    {
        this.imagePath = imagePath;
        this.thumbnailWidthAndHeight = thumbnailWidthAndHeight;
    }

    // [...]
    // getters and setters for the instance variables. image and thumbnail are lazy loaded from the imagePath.
}
Contract.java

public class MainActivity extends Activity
{
    private static final int REQUEST_CONTRACT = 1;

    private Contract contract;

    public void addContract(View view)
    {
        Intent intent = new Intent(this, ContractActivity.class);
        intent.putExtra(ContractActivity.EXTRA_CONTRACT, this.contract);
        startActivityForResult(intent, MainActivity.REQUEST_CONTRACT);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent)
    {
        if ((requestCode == REQUEST_CONTRACT) && (resultCode == RESULT_OK))
        {
            this.contract = (Contract) intent.getSerializableExtra(ContractActivity.EXTRA_CONTRACT);   
        }
        super.onActivityResult(requestCode, resultCode, intent);
    }
}
public class ContractActivity extends Activity
{
    public static final String EXTRA_CONTRACT = "ContractKey";
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null)
        {
            this.contract = (Contract) savedInstanceState.get(EXTRA_CONTRACT);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        outState.putSerializable(EXTRA_CONTRACT, this.contract);
        super.onSaveInstanceState(outState);
    }

    /**
     * Set up the {@link android.app.ActionBar}.
     */
    private void setupActionBar()
    {
        getActionBar().setDisplayHomeAsUpEnabled(true);
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch (item.getItemId())
        {
            case android.R.id.home:
                // This ID represents the Home or Up button. In the case of this
                // activity, the Up button is shown. Use NavUtils to allow users
                // to navigate up one level in the application structure. For
                // more details, see the Navigation pattern on Android Design:
                //
                // http://developer.android.com/design/patterns/navigation.html#up-vs-back
                //

                Intent result = new Intent();
                result.putExtra(EXTRA_CONTRACT, this.contract);
                setResult(Activity.RESULT_OK, result);
                // use finish instead of navigateUp which ensures the same instance
                // of the calling activity is restarted which should cause the form
                // in the MainActivity to retain entered text etc.
                finish();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    // [...]
    // other methods that add pages to this.contract
}
public class Contract implements Serializable, List<ContractPage>
{
    private List<ContractPage> pages;

    private static final long serialVersionUID = -708359261524732081L;

    public Contract()
    {
        this.pages = new ArrayList<ContractPage>();
    }

    // [...]
    // implementations of all the other methods required by the List interface by delegating the method calls to this.pages
}
public class ContractPage implements Serializable
{

    private static final long serialVersionUID = 2721152546839021601L;

    private transient Bitmap image;
    private File imagePath;
    private transient Bitmap thumbnail;
    private int thumbnailWidthAndHeight;

    public ContractPage(File imagePath, int thumbnailWidthAndHeight)
    {
        this.imagePath = imagePath;
        this.thumbnailWidthAndHeight = thumbnailWidthAndHeight;
    }

    // [...]
    // getters and setters for the instance variables. image and thumbnail are lazy loaded from the imagePath.
}
更新:

另一方面,当我在启动
ContractActivity
的意图的额外数据中放入一个非空的contract对象时,问题也存在。在这种情况下,当尝试从额外数据中检索contact对象并将其转换为合约时,它也会以同样的方式失败,因为该对象实际上是一个
ArrayList
。所以至少在这种情况下是一致的