Java 在Android中作为结果(而不是原始类)返回时,实现列表反序列化为ArrayList的对象
我正在开发一款Android应用程序,用户可以使用手机摄像头扫描合同。当我希望用户添加新合同时,我会启动一个活动,让他们拍摄合同不同页面的大量图片(第二个活动通过使用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
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
。所以至少在这种情况下是一致的