jjzjj

Android Realm - 更新 RealmList 触发 IllegalArgumentException

coder 2023-12-19 原文

我正在尝试更新现有的 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;
    }
}

为了查询 Realm DB,我创建了这个辅助类:

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();
    }
    }
}

当我添加新事件卡时,我调用此 Activity :

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();
    }
}

当我拍摄新照片时,我将以前拍摄的照片的路径保存在字符串类型的 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 Exception 'value' is not a valid managed object Realm Java Doc

最佳答案

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

这里有类似的问题 Adding standalone-objects to a RealmList

您可以如下修改toRealmList:

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;
}

关于Android Realm - 更新 RealmList 触发 IllegalArgumentException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35414545/

有关Android Realm - 更新 RealmList 触发 IllegalArgumentException的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  4. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  5. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  6. objective-c - 在设置 Cocoa Pods 和安装 Ruby 更新时出错 - 2

    我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U

  7. ruby-on-rails - Rails Associations 的更新方法是什么? - 2

    这太简单了,太荒谬了,我在任何地方都找不到关于它的任何信息,包括API文档和Rails源代码:我有一个:belongs_to关联,我开始理解当您没有关联时您在Controller中调用的正常模型方法与您有关联时调用的方法略有不同。例如,我的关联在创建Controller操作时运行良好:@user=current_user@building=Building.new(params[:building])respond_todo|format|if@user.buildings.create(params[:building])#etcetera但我找不到关于更新如何工作的文档:@user

  8. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  9. ruby-on-rails - OSX Yosemite 更新破坏了 pow.cx - 2

    升级到OSXYosemite后,我现有的pow.cx安装不起作用。升级到最新的pow.cx无效。通过事件监视器重新启动它也没有成功。 最佳答案 卸载(!)并重新安装解决了这个问题。curlget.pow.cx/uninstall.sh|shcurlget.pow.cx|sh 关于ruby-on-rails-OSXYosemite更新破坏了pow.cx,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/q

  10. ruby - 将 Gitlab 从 9.3.7 更新到 9.3.8 安装 re2 时出错 - 2

    我们在Ubuntu14.04和Gitlab9.3.7上运行,运行良好。我们正在尝试更新到Gitlabv9.3.8的最新安全补丁,但它给我们这个错误:Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension.currentdirectory:/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/re2-1.0.0/ext/re2/usr/local/bin/ruby-r./siteconf20170720-19622-15i0edf.rbextconf.rbcheckingformain(

随机推荐