私は、ユーザーが携帯電話のカメラを使用して契約をスキャンできるようにする Android アプリに取り組んでいます。ユーザーに新しい契約を追加してもらいたいときは、契約のさまざまなページの写真をたくさん撮れるようにするアクティビティを開始します (その 2 番目のアクティビティは、MediaStore.ACTION_IMAGE_CAPTUREインテントを使用して行います)。それはうまくいくようで、完了したコントラクト オブジェクトを返しsetResult()て MainActivity で取得しようとしましたonActivityResult()。
@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);
}
}
ただし、オブジェクトは正しく逆シリアル化されていないため、に戻るとContract、アプリが ClassCastException (にキャストした行) でクラッシュします。ContractMainActivity
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オブジェクトは s の単なるコレクションなので、次のようContractPageに実装するように宣言しましList<ContractPage>た:
public class Contract implements Serializable, List<ContractPage>
したがって、シリアライゼーションで何か問題が発生し、Android がContractオブジェクトを として誤ってArrayListシリアライズし、ArrayList再び としてデシリアライズすると思います。これは明らかに にキャストできませんContract。
それがなぜなのか、かなり混乱しています。ArrayList を拡張していたら、スーパークラスがシリアライゼーションを台無しにしている可能性があると考えていたでしょうが、ここにある唯一のスーパークラスObjectはインターフェイスを実装してもシリアライゼーションに影響を与えるべきではありませんか?
また、次のようにContractオブジェクトを保存します。onSaveInstanceState()
@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);
}
}
ContractActivity.java
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
}
Contract.java
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
}
ContractPage.java
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.
}
アップデート:
を開始するインテントの追加データに null 以外のコントラクト オブジェクトを配置すると、問題は逆にも存在しますContractActivity。その場合、extra-data から contact オブジェクトを取得してコントラクトにキャストしようとすると、同じように失敗します。これは、オブジェクトが実際には であるため失敗しますArrayList。したがって、少なくともその場合は一貫しています。