1

我正在开发一个 Android 应用程序,该应用程序允许用户使用手机的摄像头扫描他们的合同。当我希望用户添加新合同时,我会启动一个活动,让他们拍摄合同不同页面的许多照片(第二个活动依次使用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对象未正确反序列化,这导致应用程序在Contract返回到时因 ClassCastException 崩溃(在我将其转换为的行中)MainActivity

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对象只是ContractPages 的集合,所以我声明它List<ContractPage>像这样实现:

public class Contract implements Serializable, List<ContractPage>

因此,我认为序列化出了点问题,Android 将我的Contract对象错误地ArrayList序列化为 an 然后再反序列化为 an 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.
}

更新:

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

4

0 回答 0