当前位置: 首页 > 知识库问答 >
问题:

Android Realm-更新RealmList触发IllegalArgumentExcure

田彬郁
2023-03-14

我正在尝试更新现有的RealmObject(IncidentCard),其中包含IncidentPhoto类型的RealmList。只要我不尝试更新RealmList,对象就不会出现任何问题,当我包含列表时,我会收到以下错误消息:

E/AndroidRuntime: FATAL EXCEPTION: main
E/AndroidRuntime: Process: com.trollvik.android.incidents247, PID: 31923
E/AndroidRuntime: java.lang.IllegalArgumentException: Each element of 'value' must be a valid managed object.
E/AndroidRuntime:     at io.realm.IncidentCardRealmProxy.setPhotos(IncidentCardRealmProxy.java:218)
E/AndroidRuntime:     at com.trollvik.android.incidents247.activities.EditCardActivity.saveIncidentCard(EditCardActivity.java:155)
E/AndroidRuntime:     at com.trollvik.android.incidents247.activities.EditCardActivity$1.onClick(EditCardActivity.java:95)
E/AndroidRuntime:     at android.view.View.performClick(View.java:5197)
E/AndroidRuntime:     at android.view.View$PerformClick.run(View.java:20926)
E/AndroidRuntime:     at android.os.Handler.handleCallback(Handler.java:739)
E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:95)
E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:145)
E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5944)
E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)

这是IncidentCard类:

public class IncidentCard extends RealmObject {

    @PrimaryKey
    private long id;

    private String timestamp;
    private String type;
    private RealmList<IncidentPhoto> photos;

    public IncidentCard() {

    }

    public IncidentCard(long id, String timestamp, String type){
    this.id = id;
    this.timestamp = timestamp;
    this.type = type;
    }

    public IncidentCard(long id, String timestamp, String type, RealmList<IncidentPhoto> photos){
    this.id = id;
    this.timestamp = timestamp;
    this.type = type;
    this.photos = photos;
    }

    public long getId() {
    return this.id;
    }

    public void setId(long id) {
    this.id = id;
    }

    public String getTimestamp(){
    return this.timestamp;
    }

    public void setTimestamp(String timestamp) {
    this.timestamp = timestamp;
    }

    public String getType(){
    return this.type;
    }

    public void setType(String type){
    this.type = type;
    }

    public RealmList<IncidentPhoto> getPhotos() {
    return this.photos;
    }

    public void setPhotos(RealmList<IncidentPhoto> photos) {
    this.photos = photos;
    }
}

这是IncidentPhoto类:

public class IncidentPhoto extends RealmObject {

    private String photoPath;

    public IncidentPhoto() {

    }

    public IncidentPhoto(String photoPath) {
    this.photoPath = photoPath;
    }

    public String getPhotoPath(){
    return this.photoPath;
    }

    public void setPhotoPath(String photoPath){
    this.photoPath = photoPath;
    }
}

要查询域数据库,我创建了这个helper类:

public class IncidentDbHelper {

    private Realm realm;

    public IncidentDbHelper(Context context) {
    realm = Realm.getInstance(context);
    }

    public void setObject(IncidentCard incidentCard) {
    realm.beginTransaction();
    IncidentCard incident = realm.copyToRealmOrUpdate(incidentCard);
    realm.commitTransaction();
    }

    public IncidentCard getObject(Long id) {
    return realm.where(IncidentCard.class).equalTo("id", id).findFirst();
    }

    public void close(){
    if (realm != null) {
        realm.close();
    }
    }
}

当我添加新的事件卡时,我将此活动称为:

public class NewCardActivity extends AppCompatActivity {

    private static final int REQUEST_IMAGE_CAPTURE = 1;
    private static final String INSTANCE_STATE = "currentPhotoPath";
    private static final String INSTANCE_STATE_LIST = "currentPhotoList";

    private Context mContext;

    private IncidentCard mIncidentCard;

    private IncidentDbHelper mDbHelper;
    private IncidentCardId mIncidentId;
    private IncidentCardTimestamp mIncidentTimestamp;
    private RealmConverter mRealmConverter;

    private Resources mRes;
    private PhotoPath mPath;

    private String mCurrentPhotoPath;
    private ArrayList<String> mCurrentPhotoList;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mContext = this;
    mDbHelper = new IncidentDbHelper(mContext);
    mIncidentCard = new IncidentCard();
    mRealmConverter = new RealmConverter();
    mCurrentPhotoList = new ArrayList<String>();
    mIncidentId = new IncidentCardId();
    mIncidentTimestamp = new IncidentCardTimestamp();
    mRes = getResources();
    mPath = new PhotoPath();

    // If savedInstanceState is empty, ignore this code.
    if(savedInstanceState != null){
        mCurrentPhotoPath = savedInstanceState.getString(INSTANCE_STATE);
        mCurrentPhotoList = savedInstanceState.getStringArrayList(INSTANCE_STATE_LIST);
    }
    }

    protected void saveIncidentCard(){
    Realm realm = Realm.getInstance(this);
    Spinner spinner = (Spinner) findViewById(R.id.content_new_card_type);
    String incidentType = spinner.getSelectedItem().toString();

    realm.beginTransaction();
    mIncidentCard.setId(mIncidentId.getNewId());
    mIncidentCard.setTimestamp(mIncidentTimestamp.getNewTimestamp());
    mIncidentCard.setType(incidentType);
    mIncidentCard.setPhotos(mRealmConverter.toRealmList(mCurrentPhotoList));
    realm.commitTransaction();

    mDbHelper.setObject(mIncidentCard);
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_new_photo:
            dispatchTakePictureIntent();

        default:
            // If we got here, the user's action was not recognized.
            // Invoke the superclass to handle it.
            return super.onOptionsItemSelected(item);

    }
    }


    private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File imageFile = null;

    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        try {
            imageFile = mPath.createImageFile();
            mCurrentPhotoPath = imageFile.getAbsolutePath();
        } catch (java.io.IOException e) {
            Log.e(TAG, e.toString());
        }

        // Continue only if the File was successfully created
        if (imageFile != null) {
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                    Uri.fromFile(imageFile.getAbsoluteFile()));
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
        }
    }
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString(INSTANCE_STATE, mCurrentPhotoPath);
    savedInstanceState.putStringArrayList(INSTANCE_STATE_LIST, mCurrentPhotoList);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        mCurrentPhotoList.add(mCurrentPhotoPath);
    }
    }

    @Override
    protected void onDestroy() {
    super.onDestroy();
    mDbHelper.close();
    }
}

当我捕获新照片时,我将以前捕获的照片的路径保存在String类型的ArrayList中。在我设置IncidentCard对象的路径列表之前,我将列表转换为RealmList。这部分似乎工作得很好。

尝试在EditCardActivity中保存现有对象后出现问题:

public class EditCardActivity extends AppCompatActivity {

    private static final String INTENT_EXTRA = "EXTRA_INCIDENT_ID";
    private static final int REQUEST_IMAGE_CAPTURE = 2;
    private static final String INSTANCE_STATE = "currentPhotoPath";
    private static final String INSTANCE_STATE_LIST = "currentPhotoList";

    private Context mContext;
    private Long mIncidentId;
    private IncidentCard mIncidentCard;
    private IncidentDbHelper mDbHelper;

    private IncidentCardTimestamp mIncidentTimestamp;
    private RealmConverter mRealmConverter;

    private Resources mRes;
    private PhotoPath mPath;

    Spinner mSpinnerType;
    private String mCurrentPhotoPath;
    private ArrayList<String> mCurrentPhotoList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mRealmConverter = new RealmConverter();

    mContext = this;
    mDbHelper = new IncidentDbHelper(mContext);
    mIncidentCard = new IncidentCard();
    mCurrentPhotoList = new ArrayList<String>();
    mIncidentTimestamp = new IncidentCardTimestamp();
    mRes = getResources();
    mPath = new PhotoPath();

    // If savedInstanceState is empty, ignore this code.
    if(savedInstanceState != null){
        mCurrentPhotoPath = savedInstanceState.getString(INSTANCE_STATE);
        mCurrentPhotoList = savedInstanceState.getStringArrayList(INSTANCE_STATE_LIST);
    }

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            saveIncidentCard();
            finish();
        }
    });

    // Get Incident ID passed from Main Activity
    Intent intent = getIntent();
    mIncidentId = intent.getLongExtra(INTENT_EXTRA, 0);

    mIncidentCard = mDbHelper.getObject(mIncidentId);

    mTextViewId = (TextView) findViewById(R.id.content_edit_card_id);
    mSpinnerType = (Spinner) findViewById(R.id.content_edit_card_type);

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_dropdown_item, items);
    mSpinnerType.setAdapter(adapter);
    String compareValue = mIncidentCard.getType();
    if (!compareValue.equals(null)) {
        int spinnerPosition = adapter.getPosition(compareValue);
        mSpinnerType.setSelection(spinnerPosition);
    }

    mCurrentPhotoList = mRealmConverter.toArrayList(mIncidentCard.getPhotos());
    }

    protected void saveIncidentCard(){
    Realm realm = Realm.getInstance(this);
    Spinner spinner = (Spinner) findViewById(R.id.content_edit_card_type);

    String incidentType = spinner.getSelectedItem().toString();

    realm.beginTransaction();
    mIncidentCard.setTimestamp(mIncidentTimestamp.getNewTimestamp());
    mIncidentCard.setType(incidentType);
    mIncidentCard.setPhotos(mRealmConverter.toRealmList(mCurrentPhotoList));
    realm.commitTransaction();

    mDbHelper.setObject(mIncidentCard);
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_edit_photo:
            dispatchTakePictureIntent();

        default:
            // If we got here, the user's action was not recognized.
            // Invoke the superclass to handle it.
            return super.onOptionsItemSelected(item);

    }
    }


    private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File imageFile = null;

    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        try {
            imageFile = mPath.createImageFile();
            mCurrentPhotoPath = imageFile.getAbsolutePath();
        } catch (java.io.IOException e) {
            Log.e(TAG, e.toString());
        }

        // Continue only if the File was successfully created
        if (imageFile != null) {
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                    Uri.fromFile(imageFile.getAbsoluteFile()));
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
        }
    }
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString(INSTANCE_STATE, mCurrentPhotoPath);
    savedInstanceState.putStringArrayList(INSTANCE_STATE_LIST, mCurrentPhotoList);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        mCurrentPhotoList.add(mCurrentPhotoPath);
    }
    }

    @Override
    protected void onDestroy() {
    super.onDestroy();
    mDbHelper.close();
    }
}

如果我把mIncidentCard注释掉。setPhotos()一切似乎都正常,但当我尝试将照片设置为IncidentCard对象时,会触发IllegalArgumentException。

这是我创建的将ArrayList转换为RealmList的方法:

public RealmList<IncidentPhoto> toRealmList(ArrayList<String> arrayList){
    mRealmList = new RealmList<IncidentPhoto>();
    for (int i = 0; i < arrayList.size(); i++){
        IncidentPhoto incidentPhoto = new IncidentPhoto();
        incidentPhoto.setPhotoPath(arrayList.get(i));
        mRealmList.add(incidentPhoto);
    }
    return mRealmList;
}

我已经为此挣扎了一段时间,我不明白我做错了什么,所以任何帮助都将不胜感激。

Realm异常值不是有效的托管对象RealmJavaDoc

共有1个答案

连志义
2023-03-14

问题是,当调用setters设置RealmList时,列表中的每个元素都必须由Realm管理。

这里有一个类似的问题:向RealmList添加独立对象

您可以按如下方式修改ToRealList

public RealmList<IncidentPhoto> toRealmList(Realm realm, ArrayList<String> arrayList) {
    mRealmList = new RealmList<IncidentPhoto>();
    for (int i = 0; i < arrayList.size(); i++){
        // Create a IncidentPhoto object which is managed by Realm.
        IncidentPhoto incidentPhoto = realm.createObject(IncidentPhoto.class);
        incidentPhoto.setPhotoPath(arrayList.get(i));
        mRealmList.add(incidentPhoto);
    }
    return mRealmList;
}

public RealmList<IncidentPhoto> toRealmList(Realm realm, ArrayList<String> arrayList) {
    mRealmList = new RealmList<IncidentPhoto>();
    for (int i = 0; i < arrayList.size(); i++){
        IncidentPhoto incidentPhoto = new IncidentPhoto();
        incidentPhoto.setPhotoPath(arrayList.get(i));
        // Copy the standalone object to Realm, and get the returned object which is managed by Realm.
        incidentPhoto = realm.copyToRealm(incidentPhoto);
        mRealmList.add(incidentPhoto);
    }
    return mRealmList;
}
 类似资料:
  • userNotesTable: 用户提醒表: 插入触发器: 更新触发器: 这是数据库的当前代码,以及提醒表的特定触发器。我遇到的困难是,从提醒表中的specific中的user notes表中选择特定的名称和额外的内容,所有这些都在更新触发器中。 插入时,和会被插入到提醒和搜索表中,但我希望能够使用特定名称和用户注释表中的额外内容更新搜索表,这可能吗?

  • 问题内容: 在oracle中,我可以指定列,这将引发触发器的触发: 现在,我想执行以下操作:当 只 更新 一 列时,我不希望触发触发器。这怎么可能? 我可以列出除那一列之外的所有列,该列不应引起触发器的触发。对于具有许多列的表而言,这非常麻烦。 另一种方法是使用像这样的UPDATING函数: 但是,如果我立即更改了COL1 和 COL3,则该语句的计算结果为false。那不是我想要的,因为我只想更

  • 问题内容: 我目前正在使用基于Web的Twitter客户端,因此我使用了angular.js,node.js和socket.io。我通过socket.io将新的推文推到我的客户端,服务在其中等待新的推文。当一条新的推文到来时,该服务通过$ broadcast发送事件。 在我的控制器中是一个事件侦听器,其中传入的tweet在单独的函数中进行处理。此功能只是将新的推文推入我的推文范围。 现在,我的问题

  • 我对机会产品(i.e.line项)使用存储在Opp本身中的opp术语进行计算(例如:OLI. RecurringAmt=OPP. Term*OLI. UniPRICE*OLI. QUANTITY) 如果Opp中的术语(整数)的值发生变化,则需要手动更新每个OLI中的数学值。我建议在Opp上使用触发器,以便在术语更改时进行此更新。 问题是:由于Opp中的金额字段由SFDC自动计算为每个相关行项目的单

  • 问题内容: 我是SQL的新手,有人可以帮助我修复触发器问题吗? 我有这两个表(“评论”和“报价”),我想更新“评论”表,然后在“插入”,“更新”和“删除”中获取要约表中的数据。如果更新成功,我想使用ReviewId和ReviewDate更新商品表。 我正在使用Azure提供的SQL Server。 UserKey和Asin是唯一的值,所以这就是我用来链接这些表的东西。我将非常感谢您的帮助! 桌子:

  • 问题内容: 我正在尝试为我的表创建一个触发器,该触发器根据某个标志设置为“ Y”的时间自动添加发布日期 我没有创建触发器的丰富经验,但到目前为止,这是我所拥有的 更新列时出现此错误 触发器“ USER.ADD_CREATE_DT”无效且重新验证失败 有任何想法吗? 谢谢 问题答案: 使用WHEN子句: 或使用IF: 在这种情况下,WHEN更合适,更有效。